GCC Code Coverage Report


Directory: ./
File: sql/handler.cc
Date: 2022-12-13 11:44:05
Exec Total Coverage
Lines: 3096 3513 88.1%
Branches: 3298 5652 58.4%

Line Branch Exec Source
1 /* Copyright (c) 2000, 2022, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 /** @file sql/handler.cc
24
25 @brief
26 Implements functions in the handler interface that are shared between all
27 storage engines.
28 */
29
30 #include "sql/handler.h"
31
32 #include <ctype.h>
33 #include <errno.h>
34 #include <limits.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <algorithm>
38 #include <atomic>
39 #include <cmath>
40 #include <list>
41 #include <random> // std::uniform_real_distribution
42 #include <string>
43 #include <string_view>
44 #include <vector>
45
46 #include "keycache.h"
47 #include "libbinlogevents/include/binlog_event.h"
48 #include "m_ctype.h"
49 #include "m_string.h"
50 #include "my_bit.h" // my_count_bits
51 #include "my_bitmap.h" // MY_BITMAP
52 #include "my_check_opt.h"
53 #include "my_dbug.h"
54 #include "my_loglevel.h"
55 #include "my_macros.h"
56 #include "my_pointer_arithmetic.h"
57 #include "my_psi_config.h"
58 #include "my_sqlcommand.h"
59 #include "my_sys.h" // MEM_DEFINED_IF_ADDRESSABLE()
60 #include "myisam.h" // TT_FOR_UPGRADE
61 #include "mysql/components/services/bits/psi_bits.h"
62 #include "mysql/components/services/log_builtins.h"
63 #include "mysql/components/services/log_shared.h"
64 #include "mysql/plugin.h"
65 #include "mysql/psi/mysql_file.h"
66 #include "mysql/psi/mysql_mutex.h"
67 #include "mysql/psi/mysql_table.h"
68 #include "mysql/psi/mysql_transaction.h"
69 #include "mysql/psi/psi_table.h"
70 #include "mysql/service_mysql_alloc.h"
71 #include "mysql_com.h"
72 #include "mysql_version.h" // MYSQL_VERSION_ID
73 #include "mysqld_error.h"
74 #include "prealloced_array.h"
75 #include "sql/auth/auth_common.h" // check_readonly() and SUPER_ACL
76 #include "sql/binlog.h" // mysql_bin_log
77 #include "sql/check_stack.h"
78 #include "sql/clone_handler.h"
79 #include "sql/current_thd.h"
80 #include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_client
81 #include "sql/dd/dd.h" // dd::get_dictionary
82 #include "sql/dd/dictionary.h" // dd:acquire_shared_table_mdl
83 #include "sql/dd/types/table.h" // dd::Table
84 #include "sql/dd_table_share.h" // open_table_def
85 #include "sql/debug_sync.h" // DEBUG_SYNC
86 #include "sql/derror.h" // ER_DEFAULT
87 #include "sql/error_handler.h" // Internal_error_handler
88 #include "sql/field.h"
89 #include "sql/item.h"
90 #include "sql/lock.h" // MYSQL_LOCK
91 #include "sql/log.h"
92 #include "sql/log_event.h" // Write_rows_log_event
93 #include "sql/mdl.h"
94 #include "sql/mysqld.h" // global_system_variables heap_hton ..
95 #include "sql/mysqld_thd_manager.h"
96 #include "sql/opt_costconstantcache.h" // reload_optimizer_cost_constants
97 #include "sql/opt_costmodel.h"
98 #include "sql/opt_hints.h"
99 #include "sql/protocol.h"
100 #include "sql/psi_memory_key.h"
101 #include "sql/query_options.h"
102 #include "sql/record_buffer.h" // Record_buffer
103 #include "sql/rpl_filter.h"
104 #include "sql/rpl_gtid.h"
105 #include "sql/rpl_handler.h" // RUN_HOOK
106 #include "sql/rpl_replica_commit_order_manager.h" // Commit_order_manager
107 #include "sql/rpl_rli.h" // is_atomic_ddl_commit_on_slave
108 #include "sql/rpl_write_set_handler.h" // add_pke
109 #include "sql/sdi_utils.h" // import_serialized_meta_data
110 #include "sql/session_tracker.h"
111 #include "sql/sql_base.h" // free_io_cache
112 #include "sql/sql_bitmap.h"
113 #include "sql/sql_class.h"
114 #include "sql/sql_error.h"
115 #include "sql/sql_lex.h"
116 #include "sql/sql_parse.h" // check_stack_overrun
117 #include "sql/sql_plugin.h" // plugin_foreach
118 #include "sql/sql_select.h" // actual_key_parts
119 #include "sql/sql_table.h" // build_table_filename
120 #include "sql/sql_zip_dict.h"
121 #include "sql/strfunc.h" // strnncmp_nopads
122 #include "sql/system_variables.h"
123 #include "sql/table.h"
124 #include "sql/tc_log.h"
125 #include "sql/thr_malloc.h"
126 #include "sql/transaction.h" // trans_commit_implicit
127 #include "sql/transaction_info.h"
128 #include "sql/xa.h"
129 #include "sql/xa/sql_cmd_xa.h" // Sql_cmd_xa_*
130 #include "sql_string.h"
131 #include "sql_tmp_table.h" // free_tmp_table
132 #include "template_utils.h"
133 #include "uniques.h" // Unique_on_insert
134 #include "varlen_sort.h"
135
136 /**
137 @def MYSQL_TABLE_IO_WAIT
138 Instrumentation helper for table io_waits.
139 Note that this helper is intended to be used from
140 within the handler class only, as it uses members
141 from @c handler
142 Performance schema events are instrumented as follows:
143 - in non batch mode, one event is generated per call
144 - in batch mode, the number of rows affected is saved
145 in @c m_psi_numrows, so that @c end_psi_batch_mode()
146 generates a single event for the batch.
147 @param OP the table operation to be performed
148 @param INDEX the table index used if any, or MAX_KEY.
149 @param RESULT the result of the table operation performed
150 @param PAYLOAD instrumented code to execute
151 @sa handler::end_psi_batch_mode.
152 */
153 #ifdef HAVE_PSI_TABLE_INTERFACE
154 #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) \
155 { \
156 if (m_psi != NULL) { \
157 switch (m_psi_batch_mode) { \
158 case PSI_BATCH_MODE_NONE: { \
159 PSI_table_locker *sub_locker = NULL; \
160 PSI_table_locker_state reentrant_safe_state; \
161 reentrant_safe_state.m_thread = nullptr; \
162 reentrant_safe_state.m_wait = nullptr; \
163 sub_locker = PSI_TABLE_CALL(start_table_io_wait)( \
164 &reentrant_safe_state, m_psi, OP, INDEX, __FILE__, __LINE__); \
165 PAYLOAD \
166 if (sub_locker != NULL) PSI_TABLE_CALL(end_table_io_wait) \
167 (sub_locker, 1); \
168 break; \
169 } \
170 case PSI_BATCH_MODE_STARTING: { \
171 m_psi_locker = PSI_TABLE_CALL(start_table_io_wait)( \
172 &m_psi_locker_state, m_psi, OP, INDEX, __FILE__, __LINE__); \
173 PAYLOAD \
174 if (RESULT != HA_ERR_END_OF_FILE) m_psi_numrows++; \
175 m_psi_batch_mode = PSI_BATCH_MODE_STARTED; \
176 break; \
177 } \
178 case PSI_BATCH_MODE_STARTED: \
179 default: { \
180 assert(m_psi_batch_mode == PSI_BATCH_MODE_STARTED); \
181 PAYLOAD \
182 if (RESULT != HA_ERR_END_OF_FILE) m_psi_numrows++; \
183 break; \
184 } \
185 } \
186 } else { \
187 PAYLOAD \
188 } \
189 }
190 #else
191 #define MYSQL_TABLE_IO_WAIT(OP, INDEX, RESULT, PAYLOAD) PAYLOAD
192 #endif
193
194 /**
195 @def MYSQL_TABLE_LOCK_WAIT
196 Instrumentation helper for table io_waits.
197 @param OP the table operation to be performed
198 @param FLAGS per table operation flags.
199 @param PAYLOAD the code to instrument.
200 @sa MYSQL_END_TABLE_WAIT.
201 */
202 #ifdef HAVE_PSI_TABLE_INTERFACE
203 #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \
204 { \
205 if (m_psi != NULL) { \
206 PSI_table_locker *locker; \
207 PSI_table_locker_state state; \
208 locker = PSI_TABLE_CALL(start_table_lock_wait)(&state, m_psi, OP, FLAGS, \
209 __FILE__, __LINE__); \
210 PAYLOAD \
211 if (locker != NULL) PSI_TABLE_CALL(end_table_lock_wait)(locker); \
212 } else { \
213 PAYLOAD \
214 } \
215 }
216 #else
217 #define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) PAYLOAD
218 #endif
219
220 using std::list;
221 using std::log2;
222 using std::max;
223 using std::min;
224
225 #ifdef WITH_WSREP
226 #include "wsrep_mysqld.h"
227 #include "wsrep_thd.h"
228 #include "wsrep_trans_observer.h" /* wsrep transaction hooks */
229 #include "wsrep_xid.h"
230 #endif /* WITH_WSREP */
231
232 /**
233 While we have legacy_db_type, we have this array to
234 check for dups and to find handlerton from legacy_db_type.
235 Remove when legacy_db_type is finally gone
236 */
237 static Prealloced_array<st_plugin_int *, PREALLOC_NUM_HA> se_plugin_array(
238 PSI_NOT_INSTRUMENTED);
239
240 /**
241 Array allowing to check if handlerton is builtin without
242 acquiring LOCK_plugin.
243 */
244 static Prealloced_array<bool, PREALLOC_NUM_HA> builtin_htons(
245 PSI_NOT_INSTRUMENTED);
246
247 4156503 st_plugin_int *hton2plugin(uint slot) { return se_plugin_array[slot]; }
248
249 144208 size_t num_hton2plugins() { return se_plugin_array.size(); }
250
251 27 st_plugin_int *insert_hton2plugin(uint slot, st_plugin_int *plugin) {
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 if (se_plugin_array.assign_at(slot, plugin)) return nullptr;
253
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 builtin_htons.assign_at(slot, true);
254 27 return se_plugin_array[slot];
255 }
256
257 27 st_plugin_int *remove_hton2plugin(uint slot) {
258 27 st_plugin_int *retval = se_plugin_array[slot];
259 27 se_plugin_array[slot] = NULL;
260
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 builtin_htons.assign_at(slot, false);
261 27 return retval;
262 }
263
264 1841199 const char *ha_resolve_storage_engine_name(const handlerton *db_type) {
265
1/2
✓ Branch 0 taken 1841199 times.
✗ Branch 1 not taken.
1841199 return db_type == nullptr ? "UNKNOWN" : hton2plugin(db_type->slot)->name.str;
266 }
267
268 static handlerton *installed_htons[128];
269
270 /* number of storage engines (from installed_htons[]) that support 2pc */
271 ulong total_ha_2pc = 0;
272 /* size of savepoint storage area (see ha_init) */
273 ulong savepoint_alloc_size = 0;
274
275 namespace {
276 struct Storage_engine_identifier {
277 const LEX_CSTRING canonical;
278 const LEX_CSTRING legacy;
279 };
280 const Storage_engine_identifier se_names[] = {
281 {{STRING_WITH_LEN("INNODB")}, {STRING_WITH_LEN("INNOBASE")}},
282 {{STRING_WITH_LEN("NDBCLUSTER")}, {STRING_WITH_LEN("NDB")}},
283 {{STRING_WITH_LEN("MEMORY")}, {STRING_WITH_LEN("HEAP")}},
284 {{STRING_WITH_LEN("MRG_MYISAM")}, {STRING_WITH_LEN("MERGE")}}};
285 const auto se_names_end = std::end(se_names);
286 std::vector<std::string> disabled_se_names;
287 } // namespace
288
289 const char *ha_row_type[] = {"",
290 "FIXED",
291 "DYNAMIC",
292 "COMPRESSED",
293 "REDUNDANT",
294 "COMPACT",
295 /* Reserved to be "PAGE" in future versions */ "?",
296 "?",
297 "?",
298 "?"};
299
300 const char *tx_isolation_names[] = {"READ-UNCOMMITTED", "READ-COMMITTED",
301 "REPEATABLE-READ", "SERIALIZABLE", NullS};
302 TYPELIB tx_isolation_typelib = {array_elements(tx_isolation_names) - 1, "",
303 tx_isolation_names, nullptr};
304
305 // Called for each SE to check if given db.table_name is a system table.
306 static bool check_engine_system_table_handlerton(THD *unused, plugin_ref plugin,
307 void *arg);
308
309 static int ha_discover(THD *thd, const char *db, const char *name,
310 uchar **frmblob, size_t *frmlen);
311
312 /**
313 Structure used by SE during check for system table.
314 This structure is passed to each SE handlerton and the status (OUT param)
315 is collected.
316 */
317 struct st_sys_tbl_chk_params {
318 const char *db; // IN param
319 const char *table_name; // IN param
320 bool is_sql_layer_system_table; // IN param
321 legacy_db_type db_type; // IN param
322
323 enum enum_sys_tbl_chk_status {
324 // db.table_name is not a supported system table.
325 NOT_KNOWN_SYSTEM_TABLE,
326 /*
327 db.table_name is a system table,
328 but may not be supported by SE.
329 */
330 KNOWN_SYSTEM_TABLE,
331 /*
332 db.table_name is a system table,
333 and is supported by SE.
334 */
335 SUPPORTED_SYSTEM_TABLE
336 } status; // OUT param
337 };
338
339 1396682 static plugin_ref ha_default_plugin(THD *thd) {
340
2/2
✓ Branch 0 taken 1394676 times.
✓ Branch 1 taken 2006 times.
1396682 if (thd->variables.table_plugin) return thd->variables.table_plugin;
341 2006 return my_plugin_lock(thd, &global_system_variables.table_plugin);
342 }
343
344 /** @brief
345 Return the default storage engine handlerton used for non-temp tables
346 for thread
347
348 SYNOPSIS
349 ha_default_handlerton(thd)
350 thd current thread
351
352 RETURN
353 pointer to handlerton
354 */
355 1396682 handlerton *ha_default_handlerton(THD *thd) {
356 1396682 plugin_ref plugin = ha_default_plugin(thd);
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1396682 times.
1396682 assert(plugin);
358 1396682 handlerton *hton = plugin_data<handlerton *>(plugin);
359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1396682 times.
1396682 assert(hton);
360 1396682 return hton;
361 }
362
363 /** @brief
364 Return the enforced storage engine handlerton for thread
365
366 SYNOPSIS
367 ha_enforce_handlerton(thd)
368 thd current thread
369
370 RETURN
371 pointer to handlerton
372 */
373 46 handlerton *ha_enforce_handlerton(THD *thd) {
374
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (enforce_storage_engine) {
375 const LEX_CSTRING name{enforce_storage_engine,
376 46 strlen(enforce_storage_engine)};
377
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 plugin_ref plugin = ha_resolve_by_name(thd, &name, false);
378
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (plugin) {
379 46 handlerton *hton = plugin_data<handlerton *>(plugin);
380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 assert(hton);
381 46 return hton;
382 } else {
383 my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), enforce_storage_engine,
384 enforce_storage_engine);
385 }
386 }
387 return nullptr;
388 }
389
390 206108 static plugin_ref ha_default_temp_plugin(THD *thd) {
391
2/2
✓ Branch 0 taken 206100 times.
✓ Branch 1 taken 8 times.
206108 if (thd->variables.temp_table_plugin) return thd->variables.temp_table_plugin;
392 8 return my_plugin_lock(thd, &global_system_variables.temp_table_plugin);
393 }
394
395 /** @brief
396 Return the default storage engine handlerton used for explicitly
397 created temp tables for a thread
398
399 SYNOPSIS
400 ha_default_temp_handlerton(thd)
401 thd current thread
402
403 RETURN
404 pointer to handlerton
405 */
406 206108 handlerton *ha_default_temp_handlerton(THD *thd) {
407 206108 plugin_ref plugin = ha_default_temp_plugin(thd);
408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 206108 times.
206108 assert(plugin);
409 206108 handlerton *hton = plugin_data<handlerton *>(plugin);
410
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 206108 times.
206108 assert(hton);
411 206108 return hton;
412 }
413
414 /**
415 Resolve handlerton plugin by name, without checking for "DEFAULT" or
416 HTON_NOT_USER_SELECTABLE.
417
418 @param thd Thread context.
419 @param name Plugin name.
420
421 @return plugin or NULL if not found.
422 */
423 5663505 plugin_ref ha_resolve_by_name_raw(THD *thd, const LEX_CSTRING &name) {
424 5663505 return plugin_lock_by_name(thd, name, MYSQL_STORAGE_ENGINE_PLUGIN);
425 }
426
427 590606 static const CHARSET_INFO &hton_charset() { return *system_charset_info; }
428
429 /**
430 Return the storage engine handlerton for the supplied name.
431
432 @param thd Current thread. May be nullptr, (e.g. during initialize).
433 @param name Name of storage engine.
434 @param is_temp_table true if table is a temporary table.
435
436 @return Pointer to storage engine plugin handle.
437 */
438 608299 plugin_ref ha_resolve_by_name(THD *thd, const LEX_CSTRING *name,
439 bool is_temp_table) {
440
5/8
✓ Branch 0 taken 588665 times.
✓ Branch 1 taken 19634 times.
✓ Branch 2 taken 588666 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 588666 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 608300 times.
608299 if (thd && 0 == strnncmp_nopads(hton_charset(), *name,
441 {STRING_WITH_LEN("DEFAULT")})) {
442 return is_temp_table ? ha_default_plugin(thd) : ha_default_temp_plugin(thd);
443 }
444
445 // Note that thd CAN be nullptr here - it is not actually needed by
446 // ha_resolve_by_name_raw().
447 608300 plugin_ref plugin = ha_resolve_by_name_raw(thd, *name);
448
2/2
✓ Branch 0 taken 499 times.
✓ Branch 1 taken 607801 times.
608300 if (plugin == nullptr) {
449 // If we fail to resolve the name passed in, we try to see if it is a
450 // historical alias.
451
2/2
✓ Branch 0 taken 394 times.
✓ Branch 1 taken 105 times.
499 auto match = std::find_if(
452 std::begin(se_names), se_names_end,
453 1695 [&](const Storage_engine_identifier &sei) {
454 1695 return (0 == strnncmp_nopads(hton_charset(), *name, sei.legacy));
455 });
456
2/2
✓ Branch 0 taken 394 times.
✓ Branch 1 taken 105 times.
499 if (match != se_names_end) {
457 // if it is, we resolve using the new name
458 394 plugin = ha_resolve_by_name_raw(thd, match->canonical);
459 }
460 }
461
2/2
✓ Branch 0 taken 608195 times.
✓ Branch 1 taken 105 times.
608300 if (plugin != nullptr) {
462 608195 handlerton *hton = plugin_data<handlerton *>(plugin);
463
2/4
✓ Branch 0 taken 608195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 608195 times.
✗ Branch 3 not taken.
608195 if (hton && !(hton->flags & HTON_NOT_USER_SELECTABLE)) return plugin;
464
465 /*
466 unlocking plugin immediately after locking is relatively low cost.
467 */
468 plugin_unlock(thd, plugin);
469 }
470 105 return nullptr;
471 }
472
473 /**
474 Read a comma-separated list of storage engine names. Look up each in the
475 known list of canonical and legacy names. In case of a match; add both the
476 canonical and the legacy name to disabled_se_names, which is a static vector
477 of disabled storage engine names.
478 If there is no match, the unmodified name is added to the vector.
479 */
480 9359 void set_externally_disabled_storage_engine_names(const char *disabled_list) {
481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9359 times.
9359 assert(disabled_list != nullptr);
482
483 18718 myu::Split(
484
1/2
✓ Branch 0 taken 9359 times.
✗ Branch 1 not taken.
9359 disabled_list, disabled_list + strlen(disabled_list), myu::IsComma,
485 12 [](const char *f, const char *l) {
486
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 auto tr = myu::FindTrimmedRange(f, l, myu::IsSpace);
487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
17 if (tr.first == tr.second) return;
488
489 12 const LEX_CSTRING dse{tr.first,
490 12 static_cast<size_t>(tr.second - tr.first)};
491
3/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 7 times.
12 auto match = std::find_if(
492 std::begin(se_names), se_names_end,
493 33 [&](const Storage_engine_identifier &seid) {
494 return (
495
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4 times.
62 (0 == strnncmp_nopads(hton_charset(), dse, seid.canonical)) ||
496
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 26 times.
62 (0 == strnncmp_nopads(hton_charset(), dse, seid.legacy)));
497 });
498
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 if (match == se_names_end) {
499
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 disabled_se_names.emplace_back(dse.str, dse.length);
500 5 return;
501 }
502 7 disabled_se_names.emplace_back(match->canonical.str,
503
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 match->canonical.length);
504
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 disabled_se_names.emplace_back(match->legacy.str, match->legacy.length);
505 });
506 9359 }
507
508 646828 static bool is_storage_engine_name_externally_disabled(const char *name) {
509 646828 const LEX_CSTRING n{name, strlen(name)};
510
1/2
✓ Branch 0 taken 646828 times.
✗ Branch 1 not taken.
646828 return std::any_of(
511 disabled_se_names.begin(), disabled_se_names.end(),
512 184 [&](const std::string &dse) {
513
1/2
✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
184 return (0 == strnncmp_nopads(hton_charset(), n,
514 368 {dse.c_str(), dse.length()}));
515 1293656 });
516 }
517
518 /**
519 Returns true if the storage engine of the handlerton argument has
520 been listed in the disabled_storage_engines system variable. @note
521 that the SE may still be internally enabled, that is
522 HaIsInternallyEnabled may return true.
523 */
524 646828 bool ha_is_externally_disabled(const handlerton &htnr) {
525 646828 const char *se_name = ha_resolve_storage_engine_name(&htnr);
526
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 646828 times.
646828 assert(se_name != nullptr);
527 646828 return is_storage_engine_name_externally_disabled(se_name);
528 }
529
530 // Check if storage engine is disabled for table/tablespace creation.
531 27277 bool ha_is_storage_engine_disabled(handlerton *se_handle) {
532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27277 times.
27277 assert(se_handle != nullptr);
533 27277 return ha_is_externally_disabled(*se_handle);
534 }
535
536 1582761 plugin_ref ha_lock_engine(THD *thd, const handlerton *hton) {
537
2/2
✓ Branch 0 taken 1543646 times.
✓ Branch 1 taken 39115 times.
1582761 if (hton) {
538
1/2
✓ Branch 0 taken 1543646 times.
✗ Branch 1 not taken.
1543646 st_plugin_int **plugin = &se_plugin_array[hton->slot];
539
540 #ifdef NDEBUG
541 /*
542 Take a shortcut for builtin engines -- return pointer to plugin
543 without acquiring LOCK_plugin mutex. This is safe safe since such
544 plugins are not deleted until shutdown and we don't do reference
545 counting in non-debug builds for them.
546
547 Since we have reference to handlerton on our hands, this method
548 can't be called concurrently to non-builtin handlerton initialization/
549 deinitialization. So it is safe to access builtin_htons[] without
550 additional locking.
551 */
552 if (builtin_htons[hton->slot]) return *plugin;
553
554 return my_plugin_lock(thd, plugin);
555 #else
556 /*
557 We can't take shortcut in debug builds.
558 At least assert that builtin_htons[slot] is set correctly.
559 */
560
2/4
✓ Branch 0 taken 1543646 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1543646 times.
1543646 assert(builtin_htons[hton->slot] == (plugin[0]->plugin_dl == nullptr));
561
1/2
✓ Branch 0 taken 1543647 times.
✗ Branch 1 not taken.
1543646 return my_plugin_lock(thd, &plugin);
562 #endif
563 }
564 39115 return nullptr;
565 }
566
567 572463 handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type) {
568 plugin_ref plugin;
569
3/3
✓ Branch 0 taken 2798 times.
✓ Branch 1 taken 472864 times.
✓ Branch 2 taken 96801 times.
572463 switch (db_type) {
570 2798 case DB_TYPE_DEFAULT:
571 2798 return ha_default_handlerton(thd);
572 472864 default:
573
4/6
✓ Branch 0 taken 472864 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 472864 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 472854 times.
✓ Branch 5 taken 11 times.
945729 if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT &&
574
2/2
✓ Branch 0 taken 472854 times.
✓ Branch 1 taken 11 times.
472864 (plugin = ha_lock_engine(thd, installed_htons[db_type])))
575 472854 return plugin_data<handlerton *>(plugin);
576 [[fallthrough]];
577 case DB_TYPE_UNKNOWN:
578 96812 return nullptr;
579 }
580 }
581
582 /**
583 Use other database handler if databasehandler is not compiled in.
584 */
585 104757 handlerton *ha_checktype(THD *thd, enum legacy_db_type database_type,
586 bool no_substitute, bool report_error) {
587
1/2
✓ Branch 0 taken 104757 times.
✗ Branch 1 not taken.
104757 DBUG_TRACE;
588
1/2
✓ Branch 0 taken 104757 times.
✗ Branch 1 not taken.
104757 handlerton *hton = ha_resolve_by_legacy_type(thd, database_type);
589
2/2
✓ Branch 0 taken 7945 times.
✓ Branch 1 taken 96812 times.
104757 if (ha_storage_engine_is_enabled(hton)) return hton;
590
591
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96812 times.
96812 if (no_substitute) {
592 if (report_error) {
593 const char *engine_name = ha_resolve_storage_engine_name(hton);
594 my_error(ER_FEATURE_DISABLED, MYF(0), engine_name, engine_name);
595 }
596 return nullptr;
597 }
598
599 #ifdef WITH_WSREP
600
1/2
✓ Branch 0 taken 96812 times.
✗ Branch 1 not taken.
96812 (void)wsrep_after_rollback(thd, false);
601 #endif /* WITH_WSREP */
602
603
4/6
✓ Branch 0 taken 96812 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 826 times.
✓ Branch 3 taken 95986 times.
✓ Branch 4 taken 826 times.
✗ Branch 5 not taken.
96812 (void)RUN_HOOK(transaction, after_rollback, (thd, false));
604
605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96812 times.
96812 switch (database_type) {
606 case DB_TYPE_MRG_ISAM:
607 return ha_resolve_by_legacy_type(thd, DB_TYPE_MRG_MYISAM);
608 96812 default:
609 96812 break;
610 }
611
612
1/2
✓ Branch 0 taken 96812 times.
✗ Branch 1 not taken.
96812 return ha_default_handlerton(thd);
613 104757 } /* ha_checktype */
614
615 /**
616 Create handler object for the table in the storage engine.
617
618 @param share TABLE_SHARE for the table, can be NULL if caller
619 didn't perform full-blown open of table definition.
620 @param partitioned Indicates whether table is partitioned.
621 @param alloc Memory root to be used for allocating handler object.
622 @param db_type Table's storage engine.
623
624 @note This function will try to use default storage engine if one which
625 was specified through db_type parameter is not available.
626 */
627 12221996 handler *get_new_handler(TABLE_SHARE *share, bool partitioned, MEM_ROOT *alloc,
628 handlerton *db_type) {
629 handler *file;
630
1/2
✓ Branch 0 taken 12222011 times.
✗ Branch 1 not taken.
12221996 DBUG_TRACE;
631
5/8
✓ Branch 0 taken 12222006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12222008 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✓ Branch 5 taken 12221668 times.
✓ Branch 6 taken 340 times.
✗ Branch 7 not taken.
12222011 DBUG_PRINT("enter", ("alloc: %p", alloc));
632
633
6/6
✓ Branch 0 taken 12182904 times.
✓ Branch 1 taken 39104 times.
✓ Branch 2 taken 12182903 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 12182897 times.
✓ Branch 5 taken 6 times.
12222008 if (db_type && db_type->state == SHOW_OPTION_YES && db_type->create) {
634
2/4
✓ Branch 0 taken 12182904 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12182904 times.
✗ Branch 3 not taken.
12182897 if ((file = db_type->create(db_type, share, partitioned, alloc)))
635
1/2
✓ Branch 0 taken 12182900 times.
✗ Branch 1 not taken.
12182904 file->init();
636 12182900 return file;
637 }
638 /*
639 Try the default table type
640 Here the call to current_thd() is ok as we call this function a lot of
641 times but we enter this branch very seldom.
642 */
643
1/2
✓ Branch 0 taken 39104 times.
✗ Branch 1 not taken.
39104 return get_new_handler(share, partitioned, alloc,
644
2/4
✓ Branch 0 taken 39104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39104 times.
✗ Branch 3 not taken.
78215 ha_default_handlerton(current_thd));
645 12222004 }
646
647 static const char **handler_errmsgs;
648
649 25 static const char *get_handler_errmsg(int nr) {
650 25 return handler_errmsgs[nr - HA_ERR_FIRST];
651 }
652
653 /**
654 Register handler error messages for use with my_error().
655
656 @retval
657 0 OK
658 @retval
659 !=0 Error
660 */
661
662 9752 int ha_init_errors(void) {
663 #define SETMSG(nr, msg) handler_errmsgs[(nr)-HA_ERR_FIRST] = (msg)
664
665 /* Allocate a pointer array for the error message strings. */
666 /* Zerofill it to avoid uninitialized gaps. */
667
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9752 times.
9752 if (!(handler_errmsgs = static_cast<const char **>(my_malloc(
668 key_memory_errmsgs_handler, HA_ERR_ERRORS * sizeof(char *),
669 MYF(MY_WME | MY_ZEROFILL)))))
670 return 1;
671
672 /* Set the dedicated error messages. */
673 9752 SETMSG(HA_ERR_KEY_NOT_FOUND, ER_DEFAULT(ER_KEY_NOT_FOUND));
674 9752 SETMSG(HA_ERR_FOUND_DUPP_KEY, ER_DEFAULT(ER_DUP_KEY));
675 9752 SETMSG(HA_ERR_RECORD_CHANGED, "Update wich is recoverable");
676 9752 SETMSG(HA_ERR_WRONG_INDEX, "Wrong index given to function");
677 9752 SETMSG(HA_ERR_CRASHED, ER_DEFAULT(ER_NOT_KEYFILE));
678 9752 SETMSG(HA_ERR_WRONG_IN_RECORD, ER_DEFAULT(ER_CRASHED_ON_USAGE));
679 9752 SETMSG(HA_ERR_OUT_OF_MEM, "Table handler out of memory");
680 9752 SETMSG(HA_ERR_NOT_A_TABLE, "Incorrect file format '%.64s'");
681 9752 SETMSG(HA_ERR_WRONG_COMMAND, "Command not supported");
682 9752 SETMSG(HA_ERR_OLD_FILE, ER_DEFAULT(ER_OLD_KEYFILE));
683 9752 SETMSG(HA_ERR_NO_ACTIVE_RECORD, "No record read in update");
684 9752 SETMSG(HA_ERR_RECORD_DELETED, "Intern record deleted");
685 9752 SETMSG(HA_ERR_RECORD_FILE_FULL, ER_DEFAULT(ER_RECORD_FILE_FULL));
686 9752 SETMSG(HA_ERR_INDEX_FILE_FULL, "No more room in index file '%.64s'");
687 9752 SETMSG(HA_ERR_END_OF_FILE, "End in next/prev/first/last");
688 9752 SETMSG(HA_ERR_UNSUPPORTED, ER_DEFAULT(ER_ILLEGAL_HA));
689 9752 SETMSG(HA_ERR_TOO_BIG_ROW, "Too big row");
690 9752 SETMSG(HA_WRONG_CREATE_OPTION, "Wrong create option");
691 9752 SETMSG(HA_ERR_FOUND_DUPP_UNIQUE, ER_DEFAULT(ER_DUP_UNIQUE));
692 9752 SETMSG(HA_ERR_UNKNOWN_CHARSET, "Can't open charset");
693 9752 SETMSG(HA_ERR_WRONG_MRG_TABLE_DEF, ER_DEFAULT(ER_WRONG_MRG_TABLE));
694 9752 SETMSG(HA_ERR_CRASHED_ON_REPAIR, ER_DEFAULT(ER_CRASHED_ON_REPAIR));
695 9752 SETMSG(HA_ERR_CRASHED_ON_USAGE, ER_DEFAULT(ER_CRASHED_ON_USAGE));
696 9752 SETMSG(HA_ERR_LOCK_WAIT_TIMEOUT, ER_DEFAULT(ER_LOCK_WAIT_TIMEOUT));
697 9752 SETMSG(HA_ERR_LOCK_TABLE_FULL, ER_DEFAULT(ER_LOCK_TABLE_FULL));
698 9752 SETMSG(HA_ERR_READ_ONLY_TRANSACTION, ER_DEFAULT(ER_READ_ONLY_TRANSACTION));
699 9752 SETMSG(HA_ERR_LOCK_DEADLOCK, ER_DEFAULT(ER_LOCK_DEADLOCK));
700 9752 SETMSG(HA_ERR_CANNOT_ADD_FOREIGN, ER_DEFAULT(ER_CANNOT_ADD_FOREIGN));
701 9752 SETMSG(HA_ERR_NO_REFERENCED_ROW, ER_DEFAULT(ER_NO_REFERENCED_ROW_2));
702 9752 SETMSG(HA_ERR_ROW_IS_REFERENCED, ER_DEFAULT(ER_ROW_IS_REFERENCED_2));
703 9752 SETMSG(HA_ERR_NO_SAVEPOINT, "No savepoint with that name");
704 9752 SETMSG(HA_ERR_NON_UNIQUE_BLOCK_SIZE, "Non unique key block size");
705 9752 SETMSG(HA_ERR_NO_SUCH_TABLE, "No such table: '%.64s'");
706 9752 SETMSG(HA_ERR_TABLE_EXIST, ER_DEFAULT(ER_TABLE_EXISTS_ERROR));
707 9752 SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine");
708 9752 SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER_DEFAULT(ER_TABLE_DEF_CHANGED));
709 9752 SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY,
710 "FK constraint would lead to duplicate key");
711 9752 SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER_DEFAULT(ER_TABLE_NEEDS_UPGRADE));
712 9752 SETMSG(HA_ERR_TABLE_READONLY, ER_DEFAULT(ER_OPEN_AS_READONLY));
713 9752 SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER_DEFAULT(ER_AUTOINC_READ_FAILED));
714 9752 SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE));
715 9752 SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS,
716 ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS));
717 9752 SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG));
718 9752 SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT));
719 9752 SETMSG(HA_FTS_INVALID_DOCID, "Invalid InnoDB FTS Doc ID");
720 9752 SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
721 9752 SETMSG(HA_ERR_TABLESPACE_EXISTS, "Tablespace already exists");
722 9752 SETMSG(HA_ERR_TABLESPACE_MISSING, ER_DEFAULT(ER_TABLESPACE_MISSING));
723 9752 SETMSG(HA_ERR_FTS_EXCEED_RESULT_CACHE_LIMIT,
724 "FTS query exceeds result cache limit");
725 9752 SETMSG(HA_ERR_TEMP_FILE_WRITE_FAILURE,
726 ER_DEFAULT(ER_TEMP_FILE_WRITE_FAILURE));
727 9752 SETMSG(HA_ERR_INNODB_FORCED_RECOVERY, ER_DEFAULT(ER_INNODB_FORCED_RECOVERY));
728 9752 SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE,
729 "Too many words in a FTS phrase or proximity search");
730 9752 SETMSG(HA_ERR_TABLE_CORRUPT, ER_DEFAULT(ER_TABLE_CORRUPT));
731 9752 SETMSG(HA_ERR_TABLESPACE_MISSING, ER_DEFAULT(ER_TABLESPACE_MISSING));
732 9752 SETMSG(HA_ERR_TABLESPACE_IS_NOT_EMPTY,
733 ER_DEFAULT(ER_TABLESPACE_IS_NOT_EMPTY));
734 9752 SETMSG(HA_ERR_WRONG_FILE_NAME, ER_DEFAULT(ER_WRONG_FILE_NAME));
735 9752 SETMSG(HA_ERR_NOT_ALLOWED_COMMAND, ER_DEFAULT(ER_NOT_ALLOWED_COMMAND));
736 9752 SETMSG(HA_ERR_COMPUTE_FAILED, "Compute virtual column value failed");
737 9752 SETMSG(HA_ERR_DISK_FULL_NOWAIT, ER_DEFAULT(ER_DISK_FULL_NOWAIT));
738 9752 SETMSG(HA_ERR_NO_SESSION_TEMP, ER_DEFAULT(ER_NO_SESSION_TEMP));
739 9752 SETMSG(HA_ERR_WRONG_TABLE_NAME, ER_DEFAULT(ER_WRONG_TABLE_NAME));
740 9752 SETMSG(HA_ERR_TOO_LONG_PATH, ER_DEFAULT(ER_TABLE_NAME_CAUSES_TOO_LONG_PATH));
741 9752 SETMSG(HA_ERR_FTS_TOO_MANY_NESTED_EXP,
742 "Too many nested sub-expressions in a full-text search");
743 /* Register the error messages for use with my_error(). */
744 9752 return my_error_register(get_handler_errmsg, HA_ERR_FIRST, HA_ERR_LAST);
745 }
746
747 91220 int ha_finalize_handlerton(st_plugin_int *plugin) {
748 91220 handlerton *hton = (handlerton *)plugin->data;
749
1/2
✓ Branch 0 taken 91220 times.
✗ Branch 1 not taken.
91220 DBUG_TRACE;
750
751 /* hton can be NULL here, if ha_initialize_handlerton() failed. */
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91220 times.
91220 if (!hton) goto end;
753
754
2/3
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 91077 times.
✗ Branch 2 not taken.
91220 switch (hton->state) {
755 143 case SHOW_OPTION_NO:
756 case SHOW_OPTION_DISABLED:
757 143 break;
758 91077 case SHOW_OPTION_YES:
759
1/2
✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
91077 if (installed_htons[hton->db_type] == hton)
760 91077 installed_htons[hton->db_type] = nullptr;
761 91077 break;
762 };
763
764
3/4
✓ Branch 0 taken 33244 times.
✓ Branch 1 taken 57976 times.
✓ Branch 2 taken 33244 times.
✗ Branch 3 not taken.
91220 if (hton->panic) hton->panic(hton, HA_PANIC_CLOSE);
765
766
2/2
✓ Branch 0 taken 58174 times.
✓ Branch 1 taken 33046 times.
91220 if (plugin->plugin->deinit) {
767 /*
768 Today we have no defined/special behavior for uninstalling
769 engine plugins.
770 */
771
3/8
✓ Branch 0 taken 58174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 58174 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 58174 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
58174 DBUG_PRINT("info", ("Deinitializing plugin: '%s'", plugin->name.str));
772
2/4
✓ Branch 0 taken 58174 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 58174 times.
58174 if (plugin->plugin->deinit(nullptr)) {
773 DBUG_PRINT("warning", ("Plugin '%s' deinit function returned error.",
774 plugin->name.str));
775 }
776 }
777
778 /*
779 In case a plugin is uninstalled and re-installed later, it should
780 reuse an array slot. Otherwise the number of uninstall/install
781 cycles would be limited.
782 */
783
2/2
✓ Branch 0 taken 91077 times.
✓ Branch 1 taken 143 times.
91220 if (hton->slot != HA_SLOT_UNDEF) {
784 /* Make sure we are not unpluging another plugin */
785
2/4
✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91077 times.
91077 assert(se_plugin_array[hton->slot] == plugin);
786
2/4
✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91077 times.
91077 assert(hton->slot < se_plugin_array.size());
787
1/2
✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
91077 se_plugin_array[hton->slot] = NULL;
788
1/2
✓ Branch 0 taken 91077 times.
✗ Branch 1 not taken.
91077 builtin_htons[hton->slot] = false; /* Extra correctness. */
789 }
790
791
1/2
✓ Branch 0 taken 91220 times.
✗ Branch 1 not taken.
91220 my_free(hton);
792 91220 plugin->data = nullptr;
793 91220 end:
794 91220 return 0;
795 91220 }
796
797 106137 int ha_initialize_handlerton(st_plugin_int *plugin) {
798 handlerton *hton;
799
1/2
✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
106137 DBUG_TRACE;
800
3/8
✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106137 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 106137 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
106137 DBUG_PRINT("plugin", ("initialize plugin: '%s'", plugin->name.str));
801
802
1/2
✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
106137 hton = static_cast<handlerton *>(my_malloc(key_memory_handlerton_objects,
803 sizeof(handlerton),
804 MYF(MY_WME | MY_ZEROFILL)));
805
806
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106137 times.
106137 if (hton == nullptr) {
807 LogErr(ERROR_LEVEL, ER_HANDLERTON_OOM, plugin->name.str);
808 goto err_no_hton_memory;
809 }
810
811 106137 hton->slot = HA_SLOT_UNDEF;
812 /* Historical Requirement */
813 106137 plugin->data = hton; // shortcut for the future
814
6/8
✓ Branch 0 taken 106137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 106120 times.
✓ Branch 6 taken 17 times.
✓ Branch 7 taken 106120 times.
106137 if (plugin->plugin->init && plugin->plugin->init(hton)) {
815
8/16
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 17 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 17 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 17 times.
✗ Branch 15 not taken.
17 LogErr(ERROR_LEVEL, ER_PLUGIN_INIT_FAILED, plugin->name.str);
816 17 goto err;
817 }
818
819 /*
820 the switch below and hton->state should be removed when
821 command-line options for plugins will be implemented
822 */
823
3/8
✓ Branch 0 taken 106120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106120 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 106120 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
106120 DBUG_PRINT("info", ("hton->state=%d", hton->state));
824
2/3
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 105868 times.
✗ Branch 2 not taken.
106120 switch (hton->state) {
825 252 case SHOW_OPTION_NO:
826 252 break;
827 105868 case SHOW_OPTION_YES: {
828 uint tmp;
829 ulong fslot;
830 /* now check the db_type for conflict */
831
2/2
✓ Branch 0 taken 96200 times.
✓ Branch 1 taken 9668 times.
105868 if (hton->db_type <= DB_TYPE_UNKNOWN ||
832
2/4
✓ Branch 0 taken 96200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 96200 times.
96200 hton->db_type >= DB_TYPE_DEFAULT || installed_htons[hton->db_type]) {
833 9668 int idx = (int)DB_TYPE_FIRST_DYNAMIC;
834
835
3/4
✓ Branch 0 taken 9730 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 9668 times.
9730 while (idx < (int)DB_TYPE_DEFAULT && installed_htons[idx]) idx++;
836
837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9668 times.
9668 if (idx == (int)DB_TYPE_DEFAULT) {
838 LogErr(WARNING_LEVEL, ER_TOO_MANY_STORAGE_ENGINES);
839 goto err_deinit;
840 }
841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9668 times.
9668 if (hton->db_type != DB_TYPE_UNKNOWN)
842 LogErr(WARNING_LEVEL, ER_SE_TYPECODE_CONFLICT, plugin->plugin->name,
843 idx);
844 9668 hton->db_type = (enum legacy_db_type)idx;
845 }
846
847 /*
848 In case a plugin is uninstalled and re-installed later, it should
849 reuse an array slot. Otherwise the number of uninstall/install
850 cycles would be limited. So look for a free slot.
851 */
852
3/10
✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105868 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 105868 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
105868 DBUG_PRINT("plugin",
853 ("total_ha: %lu", static_cast<ulong>(se_plugin_array.size())));
854
3/4
✓ Branch 0 taken 632778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 526939 times.
✓ Branch 3 taken 105839 times.
632778 for (fslot = 0; fslot < se_plugin_array.size(); fslot++) {
855
3/4
✓ Branch 0 taken 526939 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 526910 times.
526939 if (!se_plugin_array[fslot]) break;
856 }
857
3/4
✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 105839 times.
105868 if (fslot < se_plugin_array.size())
858 29 hton->slot = fslot;
859 else {
860
1/2
✓ Branch 0 taken 105839 times.
✗ Branch 1 not taken.
105839 hton->slot = se_plugin_array.size();
861 }
862
2/4
✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105868 times.
✗ Branch 3 not taken.
211736 if (se_plugin_array.assign_at(hton->slot, plugin) ||
863
3/6
✓ Branch 0 taken 105868 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 105868 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 105868 times.
211736 builtin_htons.assign_at(hton->slot, (plugin->plugin_dl == nullptr)))
864 goto err_deinit;
865
866 105868 installed_htons[hton->db_type] = hton;
867 105868 tmp = hton->savepoint_offset;
868 105868 hton->savepoint_offset = savepoint_alloc_size;
869 105868 savepoint_alloc_size += tmp;
870
2/2
✓ Branch 0 taken 19071 times.
✓ Branch 1 taken 86797 times.
105868 if (hton->prepare) total_ha_2pc++;
871 105868 break;
872 }
873 [[fallthrough]];
874 default:
875 hton->state = SHOW_OPTION_DISABLED;
876 break;
877 }
878
879 /*
880 This is entirely for legacy. We will create a new "disk based" hton and a
881 "memory" hton which will be configurable longterm. We should be able to
882 remove partition and myisammrg.
883 */
884
5/5
✓ Branch 0 taken 9606 times.
✓ Branch 1 taken 9606 times.
✓ Branch 2 taken 9735 times.
✓ Branch 3 taken 9717 times.
✓ Branch 4 taken 67456 times.
106120 switch (hton->db_type) {
885 9606 case DB_TYPE_HEAP:
886 9606 heap_hton = hton;
887 9606 break;
888 9606 case DB_TYPE_TEMPTABLE:
889 9606 temptable_hton = hton;
890 9606 break;
891 9735 case DB_TYPE_MYISAM:
892 9735 myisam_hton = hton;
893 9735 break;
894 9717 case DB_TYPE_INNODB:
895 9717 innodb_hton = hton;
896 9717 break;
897 67456 default:
898 67456 break;
899 };
900
901 /*
902 Re-load the optimizer cost constants since this storage engine can
903 have non-default cost constants.
904 */
905
1/2
✓ Branch 0 taken 106120 times.
✗ Branch 1 not taken.
106120 reload_optimizer_cost_constants();
906
907 106120 return 0;
908
909 err_deinit:
910 /*
911 Let plugin do its inner deinitialization as plugin->init()
912 was successfully called before.
913 */
914 if (plugin->plugin->deinit) (void)plugin->plugin->deinit(nullptr);
915
916 err:
917
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 my_free(hton);
918 17 err_no_hton_memory:
919 17 plugin->data = nullptr;
920 17 return 1;
921 106137 }
922
923 9575 int ha_init() {
924 9575 int error = 0;
925
1/2
✓ Branch 0 taken 9575 times.
✗ Branch 1 not taken.
9575 DBUG_TRACE;
926
927 /*
928 Check if there is a transaction-capable storage engine besides the
929 binary log.
930 */
931 9575 opt_using_transactions =
932
1/2
✓ Branch 0 taken 9575 times.
✗ Branch 1 not taken.
9575 se_plugin_array.size() > static_cast<ulong>(opt_bin_log);
933 9575 savepoint_alloc_size += sizeof(SAVEPOINT);
934
935 9575 return error;
936 9575 }
937
938 8457 void ha_end() {
939 // Unregister handler error messages.
940 8457 my_error_unregister(HA_ERR_FIRST, HA_ERR_LAST);
941 8457 my_free(handler_errmsgs);
942 8457 }
943
944 54833 static bool dropdb_handlerton(THD *, plugin_ref plugin, void *path) {
945 54833 handlerton *hton = plugin_data<handlerton *>(plugin);
946
3/4
✓ Branch 0 taken 54810 times.
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54810 times.
54833 if (hton->state == SHOW_OPTION_YES && hton->drop_database)
947 hton->drop_database(hton, (char *)path);
948 54833 return false;
949 }
950
951 5053 void ha_drop_database(char *path) {
952 5053 plugin_foreach(nullptr, dropdb_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, path);
953 5053 }
954
955 145933751 static bool closecon_handlerton(THD *thd, plugin_ref plugin, void *) {
956 145933751 handlerton *hton = plugin_data<handlerton *>(plugin);
957 /*
958 there's no need to rollback here as all transactions must
959 be rolled back already
960 */
961
6/6
✓ Branch 0 taken 145682609 times.
✓ Branch 1 taken 251155 times.
✓ Branch 2 taken 15805875 times.
✓ Branch 3 taken 129877238 times.
✓ Branch 4 taken 15805874 times.
✓ Branch 5 taken 130128394 times.
145933764 if (hton->state == SHOW_OPTION_YES && thd_get_ha_data(thd, hton)) {
962
2/2
✓ Branch 0 taken 15805873 times.
✓ Branch 1 taken 1 times.
15805874 if (hton->close_connection) hton->close_connection(hton, thd);
963 /* make sure ha_data is reset and ha_data_lock is released */
964 15805876 thd_set_ha_data(thd, hton, nullptr);
965 }
966 145934028 return false;
967 }
968
969 /**
970 @note
971 don't bother to rollback here, it's done already
972 */
973 16360988 void ha_close_connection(THD *thd) {
974 16360988 plugin_foreach(thd, closecon_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
975 nullptr);
976 16362194 }
977
978 171311 static bool kill_handlerton(THD *thd, plugin_ref plugin, void *) {
979 171311 handlerton *hton = plugin_data<handlerton *>(plugin);
980
981
4/4
✓ Branch 0 taken 171091 times.
✓ Branch 1 taken 220 times.
✓ Branch 2 taken 15572 times.
✓ Branch 3 taken 155519 times.
171311 if (hton->state == SHOW_OPTION_YES && hton->kill_connection) {
982
2/2
✓ Branch 0 taken 1431 times.
✓ Branch 1 taken 14141 times.
15572 if (thd_get_ha_data(thd, hton)) hton->kill_connection(hton, thd);
983 }
984
985 171311 return false;
986 }
987
988 16040 void ha_kill_connection(THD *thd) {
989 #ifdef WITH_WSREP
990
2/2
✓ Branch 0 taken 467 times.
✓ Branch 1 taken 15573 times.
16040 if (thd->wsrep_aborter)
991 {
992
1/20
✗ Branch 0 not taken.
✓ Branch 1 taken 467 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
467 WSREP_DEBUG("thd is already aborted in innodb: %u", thd->wsrep_aborter);
993 467 return;
994 }
995 #endif /* WITH_WSREP */
996 15573 plugin_foreach(thd, kill_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, nullptr);
997 }
998
999 /** Invoke handlerton::pre_dd_shutdown() on a plugin.
1000 @param plugin storage engine plugin
1001 @retval false (always) */
1002 91211 static bool pre_dd_shutdown_handlerton(THD *, plugin_ref plugin, void *) {
1003 91211 handlerton *hton = plugin_data<handlerton *>(plugin);
1004
4/4
✓ Branch 0 taken 91068 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 8375 times.
✓ Branch 3 taken 82693 times.
91211 if (hton->state == SHOW_OPTION_YES && hton->pre_dd_shutdown)
1005 8375 hton->pre_dd_shutdown(hton);
1006 91197 return false;
1007 }
1008
1009 /** Invoke handlerton::pre_dd_shutdown() on every storage engine plugin. */
1010 8471 void ha_pre_dd_shutdown(void) {
1011 8471 plugin_foreach(nullptr, pre_dd_shutdown_handlerton,
1012 MYSQL_STORAGE_ENGINE_PLUGIN, nullptr);
1013 8457 }
1014
1015 /* ========================================================================
1016 ======================= TRANSACTIONS ===================================*/
1017
1018 /**
1019 Transaction handling in the server
1020 ==================================
1021
1022 In each client connection, MySQL maintains two transactional
1023 states:
1024 - a statement transaction,
1025 - a standard, also called normal transaction.
1026
1027 Historical note
1028 ---------------
1029 "Statement transaction" is a non-standard term that comes
1030 from the times when MySQL supported BerkeleyDB storage engine.
1031
1032 First of all, it should be said that in BerkeleyDB auto-commit
1033 mode auto-commits operations that are atomic to the storage
1034 engine itself, such as a write of a record, and are too
1035 high-granular to be atomic from the application perspective
1036 (MySQL). One SQL statement could involve many BerkeleyDB
1037 auto-committed operations and thus BerkeleyDB auto-commit was of
1038 little use to MySQL.
1039
1040 Secondly, instead of SQL standard savepoints, BerkeleyDB
1041 provided the concept of "nested transactions". In a nutshell,
1042 transactions could be arbitrarily nested, but when the parent
1043 transaction was committed or aborted, all its child (nested)
1044 transactions were handled committed or aborted as well.
1045 Commit of a nested transaction, in turn, made its changes
1046 visible, but not durable: it destroyed the nested transaction,
1047 all its changes would become available to the parent and
1048 currently active nested transactions of this parent.
1049
1050 So the mechanism of nested transactions was employed to
1051 provide "all or nothing" guarantee of SQL statements
1052 required by the standard.
1053 A nested transaction would be created at start of each SQL
1054 statement, and destroyed (committed or aborted) at statement
1055 end. Such nested transaction was internally referred to as
1056 a "statement transaction" and gave birth to the term.
1057
1058 (Historical note ends)
1059
1060 Since then a statement transaction is started for each statement
1061 that accesses transactional tables or uses the binary log. If
1062 the statement succeeds, the statement transaction is committed.
1063 If the statement fails, the transaction is rolled back. Commits
1064 of statement transactions are not durable -- each such
1065 transaction is nested in the normal transaction, and if the
1066 normal transaction is rolled back, the effects of all enclosed
1067 statement transactions are undone as well. Technically,
1068 a statement transaction can be viewed as a savepoint which is
1069 maintained automatically in order to make effects of one
1070 statement atomic.
1071
1072 The normal transaction is started by the user and is ended
1073 usually upon a user request as well. The normal transaction
1074 encloses transactions of all statements issued between
1075 its beginning and its end.
1076 In autocommit mode, the normal transaction is equivalent
1077 to the statement transaction.
1078
1079 Since MySQL supports PSEA (pluggable storage engine
1080 architecture), more than one transactional engine can be
1081 active at a time. Hence transactions, from the server
1082 point of view, are always distributed. In particular,
1083 transactional state is maintained independently for each
1084 engine. In order to commit a transaction the two phase
1085 commit protocol is employed.
1086
1087 Not all statements are executed in context of a transaction.
1088 Administrative and status information statements do not modify
1089 engine data, and thus do not start a statement transaction and
1090 also have no effect on the normal transaction. Examples of such
1091 statements are SHOW STATUS and RESET SLAVE.
1092
1093 Similarly DDL statements are not transactional,
1094 and therefore a transaction is [almost] never started for a DDL
1095 statement. The difference between a DDL statement and a purely
1096 administrative statement though is that a DDL statement always
1097 commits the current transaction before proceeding, if there is
1098 any.
1099
1100 At last, SQL statements that work with non-transactional
1101 engines also have no effect on the transaction state of the
1102 connection. Even though they are written to the binary log,
1103 and the binary log is, overall, transactional, the writes
1104 are done in "write-through" mode, directly to the binlog
1105 file, followed with a OS cache sync, in other words,
1106 bypassing the binlog undo log (translog).
1107 They do not commit the current normal transaction.
1108 A failure of a statement that uses non-transactional tables
1109 would cause a rollback of the statement transaction, but
1110 in case there no non-transactional tables are used,
1111 no statement transaction is started.
1112
1113 Data layout
1114 -----------
1115
1116 The server stores its transaction-related data in
1117 thd->transaction. This structure has two members of type
1118 THD_TRANS. These members correspond to the statement and
1119 normal transactions respectively:
1120
1121 - thd->transaction.stmt contains a list of engines
1122 that are participating in the given statement
1123 - thd->transaction.all contains a list of engines that
1124 have participated in any of the statement transactions started
1125 within the context of the normal transaction.
1126 Each element of the list contains a pointer to the storage
1127 engine, engine-specific transactional data, and engine-specific
1128 transaction flags.
1129
1130 In autocommit mode thd->transaction.all is empty.
1131 Instead, data of thd->transaction.stmt is
1132 used to commit/rollback the normal transaction.
1133
1134 The list of registered engines has a few important properties:
1135 - no engine is registered in the list twice
1136 - engines are present in the list a reverse temporal order --
1137 new participants are always added to the beginning of the list.
1138
1139 Transaction life cycle
1140 ----------------------
1141
1142 When a new connection is established, thd->transaction
1143 members are initialized to an empty state.
1144 If a statement uses any tables, all affected engines
1145 are registered in the statement engine list. In
1146 non-autocommit mode, the same engines are registered in
1147 the normal transaction list.
1148 At the end of the statement, the server issues a commit
1149 or a roll back for all engines in the statement list.
1150 At this point transaction flags of an engine, if any, are
1151 propagated from the statement list to the list of the normal
1152 transaction.
1153 When commit/rollback is finished, the statement list is
1154 cleared. It will be filled in again by the next statement,
1155 and emptied again at the next statement's end.
1156
1157 The normal transaction is committed in a similar way
1158 (by going over all engines in thd->transaction.all list)
1159 but at different times:
1160 - upon COMMIT SQL statement is issued by the user
1161 - implicitly, by the server, at the beginning of a DDL statement
1162 or SET AUTOCOMMIT={0|1} statement.
1163
1164 The normal transaction can be rolled back as well:
1165 - if the user has requested so, by issuing ROLLBACK SQL
1166 statement
1167 - if one of the storage engines requested a rollback
1168 by setting thd->transaction_rollback_request. This may
1169 happen in case, e.g., when the transaction in the engine was
1170 chosen a victim of the internal deadlock resolution algorithm
1171 and rolled back internally. When such a situation happens, there
1172 is little the server can do and the only option is to rollback
1173 transactions in all other participating engines. In this case
1174 the rollback is accompanied by an error sent to the user.
1175
1176 As follows from the use cases above, the normal transaction
1177 is never committed when there is an outstanding statement
1178 transaction. In most cases there is no conflict, since
1179 commits of the normal transaction are issued by a stand-alone
1180 administrative or DDL statement, thus no outstanding statement
1181 transaction of the previous statement exists. Besides,
1182 all statements that manipulate with the normal transaction
1183 are prohibited in stored functions and triggers, therefore
1184 no conflicting situation can occur in a sub-statement either.
1185 The remaining rare cases when the server explicitly has
1186 to commit the statement transaction prior to committing the normal
1187 one cover error-handling scenarios (see for example
1188 SQLCOM_LOCK_TABLES).
1189
1190 When committing a statement or a normal transaction, the server
1191 either uses the two-phase commit protocol, or issues a commit
1192 in each engine independently. The two-phase commit protocol
1193 is used only if:
1194 - all participating engines support two-phase commit (provide
1195 handlerton::prepare PSEA API call) and
1196 - transactions in at least two engines modify data (i.e. are
1197 not read-only).
1198
1199 Note that the two phase commit is used for
1200 statement transactions, even though they are not durable anyway.
1201 This is done to ensure logical consistency of data in a multiple-
1202 engine transaction.
1203 For example, imagine that some day MySQL supports unique
1204 constraint checks deferred till the end of statement. In such
1205 case a commit in one of the engines may yield ER_DUP_KEY,
1206 and MySQL should be able to gracefully abort statement
1207 transactions of other participants.
1208
1209 After the normal transaction has been committed,
1210 thd->transaction.all list is cleared.
1211
1212 When a connection is closed, the current normal transaction, if
1213 any, is rolled back.
1214
1215 Roles and responsibilities
1216 --------------------------
1217
1218 The server has no way to know that an engine participates in
1219 the statement and a transaction has been started
1220 in it unless the engine says so. Thus, in order to be
1221 a part of a transaction, the engine must "register" itself.
1222 This is done by invoking trans_register_ha() server call.
1223 Normally the engine registers itself whenever handler::external_lock()
1224 is called. trans_register_ha() can be invoked many times: if
1225 an engine is already registered, the call does nothing.
1226 In case autocommit is not set, the engine must register itself
1227 twice -- both in the statement list and in the normal transaction
1228 list.
1229 In which list to register is a parameter of trans_register_ha().
1230
1231 Note, that although the registration interface in itself is
1232 fairly clear, the current usage practice often leads to undesired
1233 effects. E.g. since a call to trans_register_ha() in most engines
1234 is embedded into implementation of handler::external_lock(), some
1235 DDL statements start a transaction (at least from the server
1236 point of view) even though they are not expected to. E.g.
1237 CREATE TABLE does not start a transaction, since
1238 handler::external_lock() is never called during CREATE TABLE. But
1239 CREATE TABLE ... SELECT does, since handler::external_lock() is
1240 called for the table that is being selected from. This has no
1241 practical effects currently, but must be kept in mind
1242 nevertheless.
1243
1244 Once an engine is registered, the server will do the rest
1245 of the work.
1246
1247 During statement execution, whenever any of data-modifying
1248 PSEA API methods is used, e.g. handler::write_row() or
1249 handler::update_row(), the read-write flag is raised in the
1250 statement transaction for the involved engine.
1251 Currently All PSEA calls are "traced", and the data can not be
1252 changed in a way other than issuing a PSEA call. Important:
1253 unless this invariant is preserved the server will not know that
1254 a transaction in a given engine is read-write and will not
1255 involve the two-phase commit protocol!
1256
1257 At the end of a statement, server call trans_commit_stmt is
1258 invoked. This call in turn invokes handlerton::prepare()
1259 for every involved engine. Prepare is followed by a call
1260 to handlerton::commit_one_phase() If a one-phase commit
1261 will suffice, handlerton::prepare() is not invoked and
1262 the server only calls handlerton::commit_one_phase().
1263 At statement commit, the statement-related read-write
1264 engine flag is propagated to the corresponding flag in the
1265 normal transaction. When the commit is complete, the list
1266 of registered engines is cleared.
1267
1268 Rollback is handled in a similar fashion.
1269
1270 Additional notes on DDL and the normal transaction.
1271 ---------------------------------------------------
1272
1273 DDLs and operations with non-transactional engines
1274 do not "register" in thd->transaction lists, and thus do not
1275 modify the transaction state. Besides, each DDL in
1276 MySQL is prefixed with an implicit normal transaction commit
1277 (a call to trans_commit_implicit()), and thus leaves nothing
1278 to modify.
1279 However, as it has been pointed out with CREATE TABLE .. SELECT,
1280 some DDL statements can start a *new* transaction.
1281
1282 Behaviour of the server in this case is currently badly
1283 defined.
1284 DDL statements use a form of "semantic" logging
1285 to maintain atomicity: if CREATE TABLE .. SELECT failed,
1286 the newly created table is deleted.
1287 In addition, some DDL statements issue interim transaction
1288 commits: e.g. ALTER TABLE issues a commit after data is copied
1289 from the original table to the internal temporary table. Other
1290 statements, e.g. CREATE TABLE ... SELECT do not always commit
1291 after itself.
1292 And finally there is a group of DDL statements such as
1293 RENAME/DROP TABLE that doesn't start a new transaction
1294 and doesn't commit.
1295
1296 This diversity makes it hard to say what will happen if
1297 by chance a stored function is invoked during a DDL --
1298 whether any modifications it makes will be committed or not
1299 is not clear. Fortunately, SQL grammar of few DDLs allows
1300 invocation of a stored function.
1301
1302 A consistent behaviour is perhaps to always commit the normal
1303 transaction after all DDLs, just like the statement transaction
1304 is always committed at the end of all statements.
1305 */
1306
1307 /**
1308 Register a storage engine for a transaction.
1309
1310 Every storage engine MUST call this function when it starts
1311 a transaction or a statement (that is it must be called both for the
1312 "beginning of transaction" and "beginning of statement").
1313 Only storage engines registered for the transaction/statement
1314 will know when to commit/rollback it.
1315
1316 @note
1317 trans_register_ha is idempotent - storage engine may register many
1318 times per transaction.
1319
1320 */
1321 117373248 void trans_register_ha(THD *thd, bool all, handlerton *ht_arg,
1322 const ulonglong *trxid [[maybe_unused]]) {
1323 Ha_trx_info *ha_info;
1324 117373248 Transaction_ctx *trn_ctx = thd->get_transaction();
1325 117374371 Transaction_ctx::enum_trx_scope trx_scope =
1326
2/2
✓ Branch 0 taken 4242345 times.
✓ Branch 1 taken 113132026 times.
117374371 all ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
1327
1328
1/2
✓ Branch 0 taken 117375245 times.
✗ Branch 1 not taken.
117374371 DBUG_TRACE;
1329
7/10
✓ Branch 0 taken 117375056 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117374546 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6686 times.
✓ Branch 5 taken 117367860 times.
✓ Branch 6 taken 201 times.
✓ Branch 7 taken 6485 times.
✓ Branch 8 taken 6686 times.
✗ Branch 9 not taken.
117375245 DBUG_PRINT("enter", ("%s", all ? "all" : "stmt"));
1330
1331
2/2
✓ Branch 0 taken 4242338 times.
✓ Branch 1 taken 113132208 times.
117374546 if (all) {
1332 /*
1333 Ensure no active backup engine data exists, unless the current
1334 transaction is from replication and in active xa state.
1335 */
1336
4/6
✓ Branch 0 taken 4242474 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 344 times.
✓ Branch 3 taken 4242130 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 344 times.
4242338 assert(
1337 thd->get_ha_data(ht_arg->slot)->ha_ptr_backup == nullptr ||
1338 (thd->get_transaction()->xid_state()->has_state(XID_STATE::XA_ACTIVE)));
1339
6/8
✓ Branch 0 taken 4242349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 344 times.
✓ Branch 3 taken 4242005 times.
✓ Branch 4 taken 340 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 340 times.
4242474 assert(thd->get_ha_data(ht_arg->slot)->ha_ptr_backup == nullptr ||
1340 (thd->is_binlog_applier() || thd->slave_thread));
1341
1342 4242349 thd->server_status |= SERVER_STATUS_IN_TRANS;
1343
2/2
✓ Branch 0 taken 1410 times.
✓ Branch 1 taken 4240939 times.
4242349 if (thd->tx_read_only)
1344 1410 thd->server_status |= SERVER_STATUS_IN_TRANS_READONLY;
1345
5/8
✓ Branch 0 taken 4242120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4242372 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 207 times.
✓ Branch 5 taken 4242165 times.
✓ Branch 6 taken 207 times.
✗ Branch 7 not taken.
4242349 DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS"));
1346 }
1347
1348
3/4
✓ Branch 0 taken 117374198 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4242445 times.
✓ Branch 3 taken 113131753 times.
117374580 ha_info = thd->get_ha_data(ht_arg->slot)->ha_info + (all ? 1 : 0);
1349
1350
2/2
✓ Branch 0 taken 83722432 times.
✓ Branch 1 taken 33651861 times.
117374198 if (ha_info->is_started()) {
1351
3/6
✓ Branch 0 taken 83722411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83722411 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 83722411 times.
83722432 assert(trn_ctx->ha_trx_info(trx_scope));
1352 83722393 return; /* already registered, return */
1353 }
1354
1355
1/2
✓ Branch 0 taken 33652885 times.
✗ Branch 1 not taken.
33651861 trn_ctx->register_ha(trx_scope, ha_info, ht_arg);
1356
1/2
✓ Branch 0 taken 33652623 times.
✗ Branch 1 not taken.
33652885 trn_ctx->set_ha_trx_info(trx_scope, ha_info);
1357
1358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33652623 times.
33652623 if (ht_arg->prepare == nullptr) trn_ctx->set_no_2pc(trx_scope, true);
1359
1360
1/2
✓ Branch 0 taken 33652744 times.
✗ Branch 1 not taken.
33652623 trn_ctx->xid_state()->set_query_id(thd->query_id);
1361 /*
1362 Register transaction start in performance schema if not done already.
1363 By doing this, we handle cases when the transaction is started
1364 implicitly in autocommit=0 mode, and cases when we are in normal autocommit=1
1365 mode and the executed statement is a single-statement transaction.
1366
1367 Explicitly started transactions are handled in trans_begin().
1368
1369 Do not register transactions in which binary log is the only
1370 participating transactional storage engine.
1371 */
1372 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
1373
2/2
✓ Branch 0 taken 22269312 times.
✓ Branch 1 taken 303691 times.
22573003 if (thd->m_transaction_psi == nullptr && ht_arg->db_type != DB_TYPE_BINLOG &&
1374 #ifdef WITH_WSREP
1375 /* Do not register transactions for WSREP engine, it would be done by the
1376 base transactional storage engine (InnoDB). */
1377
6/6
✓ Branch 0 taken 22573003 times.
✓ Branch 1 taken 11079741 times.
✓ Branch 2 taken 22269286 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 7049283 times.
✓ Branch 5 taken 26603329 times.
78494901 ht_arg->db_type != DB_TYPE_WSREP &&
1378 #endif /* WITH_WSREP */
1379
2/2
✓ Branch 0 taken 7049230 times.
✓ Branch 1 taken 15219924 times.
22269286 !thd->is_attachable_transaction_active()) {
1380 7049283 const XID *xid = trn_ctx->xid_state()->get_xid();
1381 7049341 bool autocommit = !thd->in_multi_stmt_transaction_mode();
1382
1/2
✓ Branch 0 taken 7048732 times.
✗ Branch 1 not taken.
7049245 thd->m_transaction_psi = MYSQL_START_TRANSACTION(
1383 &thd->m_transaction_state, xid, trxid, thd->tx_isolation,
1384 thd->tx_read_only, autocommit);
1385
3/4
✓ Branch 0 taken 5063954 times.
✓ Branch 1 taken 1984895 times.
✓ Branch 2 taken 5064470 times.
✗ Branch 3 not taken.
7048732 DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid");
1386
1/2
✓ Branch 0 taken 7049339 times.
✗ Branch 1 not taken.
7049365 gtid_set_performance_schema_values(thd);
1387 }
1388 #endif
1389
2/2
✓ Branch 0 taken 33652945 times.
✓ Branch 1 taken 83722440 times.
117375061 }
1390
1391 /**
1392 Check if we can skip the two-phase commit.
1393
1394 A helper function to evaluate if two-phase commit is mandatory.
1395 As a side effect, propagates the read-only/read-write flags
1396 of the statement transaction to its enclosing normal transaction.
1397
1398 If we have at least two engines with read-write changes we must
1399 run a two-phase commit. Otherwise we can run several independent
1400 commits as the only transactional engine has read-write changes
1401 and others are read-only.
1402
1403 @retval 0 All engines are read-only.
1404 @retval 1 We have the only engine with read-write changes.
1405 @retval >1 More than one engine have read-write changes.
1406 Note: return value might NOT be the exact number of
1407 engines with read-write changes.
1408 */
1409
1410 12799774 static uint ha_check_and_coalesce_trx_read_only(THD *thd,
1411 Ha_trx_info_list &ha_list,
1412 bool all) {
1413 /* The number of storage engines that have actual changes. */
1414 12799774 unsigned rw_ha_count = 0;
1415
1416
7/12
✓ Branch 0 taken 12799950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12800031 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17779076 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17243754 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30043043 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17779004 times.
✓ Branch 11 taken 12264039 times.
30043308 for (auto const &ha_info : ha_list) {
1417
3/4
✓ Branch 0 taken 17779334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15894844 times.
✓ Branch 3 taken 1884490 times.
17779076 if (ha_info.is_trx_read_write()) ++rw_ha_count;
1418
1419
2/2
✓ Branch 0 taken 16007357 times.
✓ Branch 1 taken 1771977 times.
17779334 if (!all) {
1420 Ha_trx_info *ha_info_all =
1421
1/2
✓ Branch 0 taken 16007714 times.
✗ Branch 1 not taken.
16007357 &thd->get_ha_data(ha_info.ht()->slot)->ha_info[1];
1422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16007714 times.
16007714 assert(&ha_info != ha_info_all);
1423 /*
1424 Merge read-only/read-write information about statement
1425 transaction to its enclosing normal transaction. Do this
1426 only if in a real transaction -- that is, if we know
1427 that ha_info_all is registered in thd->transaction.all.
1428 Since otherwise we only clutter the normal transaction flags.
1429 */
1430
2/2
✓ Branch 0 taken 10569854 times.
✓ Branch 1 taken 5437871 times.
16007714 if (ha_info_all->is_started()) /* false if autocommit. */
1431
1/2
✓ Branch 0 taken 10569838 times.
✗ Branch 1 not taken.
10569854 ha_info_all->coalesce_trx_with(ha_info);
1432
2/2
✓ Branch 0 taken 536152 times.
✓ Branch 1 taken 1235825 times.
1771977 } else if (rw_ha_count > 1) {
1433 /*
1434 It is a normal transaction, so we don't need to merge read/write
1435 information up, and the need for two-phase commit has been
1436 already established. Break the loop prematurely.
1437 */
1438 536152 break;
1439 }
1440 12800191 }
1441 12799863 return rw_ha_count;
1442 }
1443
1444 /**
1445 The function computes condition to call gtid persistor wrapper,
1446 and executes it.
1447 It is invoked at committing a statement or transaction, including XA,
1448 and also at XA prepare handling.
1449
1450 @param thd Thread context.
1451 @param all The execution scope, true for the transaction one, false
1452 for the statement one.
1453
1454 @return std::pair containing: Error and Owned GTID release status
1455 Error
1456 @retval 0 Ok
1457 @retval !0 Error
1458
1459 Owned GTID release status
1460 @retval true remove the GTID owned by thread from owned GTIDs
1461 @retval false removal of the GTID owned by thread from owned GTIDs
1462 is not required
1463 */
1464
1465 15548245 std::pair<int, bool> commit_owned_gtids(THD *thd, bool all) {
1466
1/2
✓ Branch 0 taken 15548939 times.
✗ Branch 1 not taken.
15548245 DBUG_TRACE;
1467 15548939 int error = 0;
1468 15548939 bool need_clear_owned_gtid = false;
1469
1470 /*
1471 If the binary log is disabled for this thread (either by
1472 log_bin=0 or sql_log_bin=0 or by log_replica_updates=0 for a
1473 slave thread), then the statement will not be written to
1474 the binary log. In this case, we should save its GTID into
1475 mysql.gtid_executed table and @@GLOBAL.GTID_EXECUTED as it
1476 did when binlog is enabled.
1477
1478 We also skip saving GTID into mysql.gtid_executed table and
1479 @@GLOBAL.GTID_EXECUTED when replica-preserve-commit-order is enabled. We
1480 skip as GTID will be saved in
1481 Commit_order_manager::flush_engine_and_signal_threads (invoked from
1482 Commit_order_manager::wait_and_finish). In particular, there is the
1483 following call stack under ha_commit_low which save GTID in case its skipped
1484 here:
1485
1486 ha_commit_low ->
1487 Commit_order_manager::wait_and_finish ->
1488 Commit_order_manager::finish ->
1489 Commit_order_manager::flush_engine_and_signal_threads ->
1490 Gtid_state::update_commit_group
1491
1492 We also skip saving GTID for intermediate commits i.e. when
1493 thd->is_operating_substatement_implicitly is enabled.
1494 */
1495
1/2
✓ Branch 0 taken 15548649 times.
✗ Branch 1 not taken.
15548939 if (thd->is_current_stmt_binlog_log_replica_updates_disabled() &&
1496
9/10
✓ Branch 0 taken 6223238 times.
✓ Branch 1 taken 9325411 times.
✓ Branch 2 taken 6223238 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2180654 times.
✓ Branch 5 taken 4042584 times.
✓ Branch 6 taken 2156515 times.
✓ Branch 7 taken 24139 times.
✓ Branch 8 taken 1960343 times.
✓ Branch 9 taken 13588306 times.
17705164 ending_trans(thd, all) && !thd->is_operating_gtid_table_implicitly &&
1497
2/2
✓ Branch 0 taken 1960343 times.
✓ Branch 1 taken 196172 times.
2156515 !thd->is_operating_substatement_implicitly) {
1498
5/6
✓ Branch 0 taken 1960343 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1954576 times.
✓ Branch 3 taken 5767 times.
✓ Branch 4 taken 194 times.
✓ Branch 5 taken 1960149 times.
3914919 if (!has_commit_order_manager(thd) &&
1499
2/2
✓ Branch 0 taken 1954405 times.
✓ Branch 1 taken 171 times.
1954576 (thd->owned_gtid.sidno > 0 ||
1500
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1954382 times.
1954405 thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS)) {
1501 194 need_clear_owned_gtid = true;
1502 }
1503
1504 /*
1505 If GTID is not persisted by SE, write it to
1506 mysql.gtid_executed table.
1507 */
1508
7/8
✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 1957751 times.
✓ Branch 2 taken 2592 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201 times.
✓ Branch 5 taken 2391 times.
✓ Branch 6 taken 201 times.
✓ Branch 7 taken 1960142 times.
1960343 if (thd->owned_gtid.sidno > 0 && !thd->se_persists_gtid()) {
1509
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 error = gtid_state->save(thd);
1510 }
1511 }
1512
1513
1/2
✓ Branch 0 taken 15548587 times.
✗ Branch 1 not taken.
31097679 return std::make_pair(error, need_clear_owned_gtid);
1514 15548587 }
1515
1516 /**
1517 @param[in] thd Thread handle.
1518 @param[in] all Session transaction if true, statement
1519 otherwise.
1520 @param[in] ignore_global_read_lock Allow commit to complete even if a
1521 global read lock is active. This can be
1522 used to allow changes to internal tables
1523 (e.g. slave status tables).
1524
1525 @retval
1526 0 ok
1527 @retval
1528 1 transaction was rolled back
1529 @retval
1530 2 error during commit, data may be inconsistent
1531
1532 @todo
1533 Since we don't support nested statement transactions in 5.0,
1534 we can't commit or rollback stmt transactions while we are inside
1535 stored functions or triggers. So we simply do nothing now.
1536 TODO: This should be fixed in later ( >= 5.1) releases.
1537 */
1538
1539 15546411 int ha_commit_trans(THD *thd, bool all, bool ignore_global_read_lock) {
1540 15546411 int error = 0;
1541 #ifdef WITH_WSREP
1542
2/2
✓ Branch 0 taken 15269884 times.
✓ Branch 1 taken 276527 times.
15546411 if (!thd->wsrep_applier) {
1543 /* While running in applier mode, PXC continue to retain its own
1544 stage information as it has better stage tracking. */
1545
1/2
✓ Branch 0 taken 15270532 times.
✗ Branch 1 not taken.
15269884 THD_STAGE_INFO(thd, stage_waiting_for_handler_commit);
1546 }
1547 #else
1548 THD_STAGE_INFO(thd, stage_waiting_for_handler_commit);
1549 #endif /* WITH_WSREP */
1550
1551 15547059 bool run_slave_post_commit = false;
1552 15547059 bool need_clear_owned_gtid = false;
1553 /*
1554 Save transaction owned gtid into table before transaction prepare
1555 if binlog is disabled, or binlog is enabled and log_replica_updates
1556 is disabled with slave SQL thread or slave worker thread.
1557 */
1558
1/2
✓ Branch 0 taken 15547666 times.
✗ Branch 1 not taken.
15547059 std::tie(error, need_clear_owned_gtid) = commit_owned_gtids(thd, all);
1559
1560 /*
1561 'all' means that this is either an explicit commit issued by
1562 user, or an implicit commit issued by a DDL.
1563 */
1564 15547485 Transaction_ctx *trn_ctx = thd->get_transaction();
1565 15547476 Transaction_ctx::enum_trx_scope trx_scope =
1566
2/2
✓ Branch 0 taken 3969600 times.
✓ Branch 1 taken 11577876 times.
15547476 all ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
1567
1568 /*
1569 "real" is a nick name for a transaction for which a commit will
1570 make persistent changes. E.g. a 'stmt' transaction inside a 'all'
1571 transaction is not 'real': even though it's possible to commit it,
1572 the changes are not durable as they might be rolled back if the
1573 enclosing 'all' transaction is rolled back.
1574 */
1575
4/4
✓ Branch 0 taken 11577877 times.
✓ Branch 1 taken 3969599 times.
✓ Branch 2 taken 3939420 times.
✓ Branch 3 taken 7638481 times.
15547476 bool is_real_trans = all || !trn_ctx->is_active(Transaction_ctx::SESSION);
1576 #ifndef NDEBUG
1577 15547500 bool transaction_to_skip = false;
1578
4/6
✓ Branch 0 taken 15547199 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3564 times.
✓ Branch 3 taken 15543635 times.
✓ Branch 4 taken 3564 times.
✗ Branch 5 not taken.
15547500 DBUG_EXECUTE_IF("replica_crash_after_commit", {
1579 transaction_to_skip = is_already_logged_transaction(thd);
1580 });
1581 #endif // NDEBUG
1582
1/2
✓ Branch 0 taken 15546649 times.
✗ Branch 1 not taken.
15547199 auto ha_info = trn_ctx->ha_trx_info(trx_scope);
1583 15546649 XID_STATE *xid_state = trn_ctx->xid_state();
1584
1585
1/2
✓ Branch 0 taken 15547589 times.
✗ Branch 1 not taken.
15547037 DBUG_TRACE;
1586
1587
6/10
✓ Branch 0 taken 15547477 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15547514 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 438 times.
✓ Branch 5 taken 15547076 times.
✓ Branch 6 taken 438 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 438 times.
✗ Branch 9 not taken.
15547589 DBUG_PRINT("info", ("all=%d thd->in_sub_stmt=%d ha_info=%p is_real_trans=%d",
1588 all, thd->in_sub_stmt, ha_info.head(), is_real_trans));
1589 /*
1590 We must not commit the normal transaction if a statement
1591 transaction is pending. Otherwise statement transaction
1592 flags will not get propagated to its normal transaction's
1593 counterpart.
1594 */
1595
3/4
✓ Branch 0 taken 11566386 times.
✓ Branch 1 taken 3981079 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11566386 times.
15547514 assert(!trn_ctx->is_active(Transaction_ctx::STMT) || !all);
1596
1597
3/6
✓ Branch 0 taken 15547407 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 15547403 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
15547465 DBUG_EXECUTE_IF("pre_commit_error", {
1598 error = true;
1599 my_error(ER_UNKNOWN_ERROR, MYF(0));
1600 });
1601
1602 /*
1603 When atomic DDL is executed on the slave, we would like to
1604 to update slave applier state as part of DDL's transaction.
1605 Call Relay_log_info::pre_commit() hook to do this before DDL
1606 gets committed in the following block.
1607 Failed atomic DDL statements should've been marked as executed/committed
1608 during statement rollback, though some like GRANT may continue until
1609 this point.
1610 When applying a DDL statement on a slave and the statement is filtered
1611 out by a table filter, we report an error "ER_SLAVE_IGNORED_TABLE" to
1612 warn slave applier thread. We need to save the DDL statement's gtid
1613 into mysql.gtid_executed system table if the binary log is disabled
1614 on the slave and gtids are enabled.
1615 */
1616
7/8
✓ Branch 0 taken 7908946 times.
✓ Branch 1 taken 7638343 times.
✓ Branch 2 taken 7908699 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24288 times.
✓ Branch 5 taken 7884411 times.
✓ Branch 6 taken 24287 times.
✓ Branch 7 taken 15522755 times.
15571577 if (is_real_trans && is_atomic_ddl_commit_on_slave(thd) &&
1617
3/4
✓ Branch 0 taken 24288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24285 times.
24288 (!thd->is_error() ||
1618
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
5 (thd->is_operating_gtid_table_implicitly &&
1619 2 thd->get_stmt_da()->mysql_errno() == ER_SLAVE_IGNORED_TABLE))) {
1620 24287 run_slave_post_commit = true;
1621
3/6
✓ Branch 0 taken 24287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24287 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24287 times.
24287 error = error || thd->rli_slave->pre_commit();
1622
1623
4/6
✓ Branch 0 taken 24287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24285 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
24287 DBUG_EXECUTE_IF("rli_pre_commit_error", {
1624 error = true;
1625 my_error(ER_UNKNOWN_ERROR, MYF(0));
1626 });
1627
4/6
✓ Branch 0 taken 24287 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 24243 times.
✓ Branch 4 taken 44 times.
✗ Branch 5 not taken.
24287 DBUG_EXECUTE_IF("replica_crash_before_commit", {
1628 /* This pre-commit crash aims solely at atomic DDL */
1629 DBUG_SUICIDE();
1630 });
1631 }
1632
1633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15546998 times.
15546998 if (thd->in_sub_stmt) {
1634 assert(0);
1635 /*
1636 Since we don't support nested statement transactions in 5.0,
1637 we can't commit or rollback stmt transactions while we are inside
1638 stored functions or triggers. So we simply do nothing now.
1639 TODO: This should be fixed in later ( >= 5.1) releases.
1640 */
1641 if (!all) return 0;
1642 /*
1643 We assume that all statements which commit or rollback main transaction
1644 are prohibited inside of stored functions or triggers. So they should
1645 bail out with error even before ha_commit_trans() call. To be 100% safe
1646 let us throw error in non-debug builds.
1647 */
1648 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
1649 return 2;
1650 }
1651
1652 15546998 MDL_request mdl_request;
1653 15547288 bool release_mdl = false;
1654 #ifdef WITH_WSREP
1655 15547288 uint rw_ha_count = 0;
1656 #endif /* WITH_WSREP */
1657
6/8
✓ Branch 0 taken 15547119 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12799858 times.
✓ Branch 3 taken 2747261 times.
✓ Branch 4 taken 12799875 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12799898 times.
✓ Branch 7 taken 2747221 times.
15547288 if (ha_info && !error) {
1658 #ifndef WITH_WSREP
1659 uint rw_ha_count = 0;
1660 #endif /* !!!!!WITH_WSREP */
1661 bool rw_trans;
1662
1663
4/6
✓ Branch 0 taken 12800014 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 12799985 times.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
12799898 DBUG_EXECUTE_IF("crash_commit_before", DBUG_SUICIDE(););
1664
1665 /*
1666 skip 2PC if the transaction is empty and it is not marked as started (which
1667 can happen when the slave's binlog is disabled)
1668 */
1669
2/4
✓ Branch 0 taken 12799827 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12799829 times.
✗ Branch 3 not taken.
12799985 if (ha_info->is_started())
1670
1/2
✓ Branch 0 taken 12799978 times.
✗ Branch 1 not taken.
12799829 rw_ha_count = ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
1671 12799955 trn_ctx->set_rw_ha_count(trx_scope, rw_ha_count);
1672 /* rw_trans is true when we in a transaction changing data */
1673
4/4
✓ Branch 0 taken 5161509 times.
✓ Branch 1 taken 7638425 times.
✓ Branch 2 taken 3465113 times.
✓ Branch 3 taken 1696396 times.
12799934 rw_trans = is_real_trans && (rw_ha_count > 0);
1674
1675
5/8
✓ Branch 0 taken 12799825 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 12799823 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
12799934 DBUG_EXECUTE_IF("dbug.enabled_commit", {
1676 const char act[] = "now signal Reached wait_for signal.commit_continue";
1677 assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
1678 };);
1679
3/4
✓ Branch 0 taken 10707022 times.
✓ Branch 1 taken 2092557 times.
✓ Branch 2 taken 10707634 times.
✗ Branch 3 not taken.
12799825 DEBUG_SYNC(thd, "ha_commit_trans_before_acquire_commit_lock");
1680
4/4
✓ Branch 0 taken 3465250 times.
✓ Branch 1 taken 9334941 times.
✓ Branch 2 taken 3022746 times.
✓ Branch 3 taken 442504 times.
12800191 if (rw_trans && !ignore_global_read_lock) {
1681 /*
1682 Acquire a metadata lock which will ensure that COMMIT is blocked
1683 by an active FLUSH TABLES WITH READ LOCK (and vice versa:
1684 COMMIT in progress blocks FTWRL).
1685
1686 We allow the owner of FTWRL to COMMIT; we assume that it knows
1687 what it does.
1688 */
1689
1/2
✓ Branch 0 taken 3022689 times.
✗ Branch 1 not taken.
3022746 MDL_REQUEST_INIT(&mdl_request, MDL_key::COMMIT, "", "",
1690 MDL_INTENTION_EXCLUSIVE, MDL_EXPLICIT);
1691
1692
5/8
✓ Branch 0 taken 3022565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3022560 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 121 times.
✓ Branch 5 taken 3022439 times.
✓ Branch 6 taken 121 times.
✗ Branch 7 not taken.
3022689 DBUG_PRINT("debug", ("Acquire MDL commit lock"));
1693 #ifdef WITH_WSREP
1694 /* Taking explicit lock will block background/applier thread from aborting
1695 a local thread lock so avoid taking this lock here.
1696 Lock is meant to protect commit against FLUSH TABLE WITH READ LOCK
1697 that may get fired when COMMIT is active. */
1698
12/14
✓ Branch 0 taken 3022561 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 396670 times.
✓ Branch 3 taken 2625891 times.
✓ Branch 4 taken 118166 times.
✓ Branch 5 taken 278504 times.
✓ Branch 6 taken 3395 times.
✓ Branch 7 taken 114771 times.
✓ Branch 8 taken 2908174 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 2908173 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 3022944 times.
3022560 if (!WSREP(thd) && thd->mdl_context.acquire_lock(
1699 &mdl_request, thd->variables.lock_wait_timeout)) {
1700
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ha_rollback_trans(thd, all);
1701 1 return 1;
1702 }
1703 #else
1704 if (thd->mdl_context.acquire_lock(&mdl_request,
1705 thd->variables.lock_wait_timeout)) {
1706 ha_rollback_trans(thd, all);
1707 return 1;
1708 }
1709 #endif /* WITH_WSREP */
1710 3022944 release_mdl = true;
1711
1712
3/4
✓ Branch 0 taken 2918001 times.
✓ Branch 1 taken 104940 times.
✓ Branch 2 taken 2917772 times.
✗ Branch 3 not taken.
3022944 DEBUG_SYNC(thd, "ha_commit_trans_after_acquire_commit_lock");
1713 }
1714
1715
7/8
✓ Branch 0 taken 3465451 times.
✓ Branch 1 taken 9334706 times.
✓ Branch 2 taken 3465454 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3118282 times.
✓ Branch 5 taken 347172 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 12800141 times.
15918425 if (rw_trans && stmt_has_updated_trans_table(ha_info) &&
1716
3/4
✓ Branch 0 taken 3118268 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 3118263 times.
3118282 check_readonly(thd, true)) {
1717
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 ha_rollback_trans(thd, all);
1718 5 error = 1;
1719 5 goto end;
1720 }
1721
1722 #ifdef WITH_WSREP
1723
5/6
✓ Branch 0 taken 12800165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4973637 times.
✓ Branch 3 taken 7826587 times.
✓ Branch 4 taken 4973632 times.
✓ Branch 5 taken 7826575 times.
12800141 if (!trn_ctx->no_2pc(trx_scope) && (trn_ctx->rw_ha_count(trx_scope) > 1))
1724
1/2
✓ Branch 0 taken 4973629 times.
✗ Branch 1 not taken.
4973632 error = tc_log->prepare(thd, all);
1725
5/6
✓ Branch 0 taken 7826608 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5948190 times.
✓ Branch 3 taken 1878445 times.
✓ Branch 4 taken 5948181 times.
✓ Branch 5 taken 1878454 times.
15653210 else if (trn_ctx->no_2pc(trx_scope) ||
1726 7826608 trn_ctx->rw_ha_count(trx_scope) == 1) {
1727 /* cache decision to run wsrep-commit-hook with log_bin=off. */
1728
1/2
✓ Branch 0 taken 5948266 times.
✗ Branch 1 not taken.
5948181 thd->run_wsrep_commit_hooks = wsrep_run_commit_hook(thd, all);
1729 }
1730 #else
1731 if (!trn_ctx->no_2pc(trx_scope) && (trn_ctx->rw_ha_count(trx_scope) > 1))
1732 error = tc_log->prepare(thd, all);
1733 #endif /* WITH_WSREP */
1734 }
1735 /*
1736 The state of XA transaction is changed to Prepared, intermediately.
1737 It's going to change to the regular NOTR at the end.
1738 The fact of the Prepared state is of interest to binary logger.
1739 */
1740
8/8
✓ Branch 0 taken 15547167 times.
✓ Branch 1 taken 403 times.
✓ Branch 2 taken 3969476 times.
✓ Branch 3 taken 11577691 times.
✓ Branch 4 taken 123 times.
✓ Branch 5 taken 3969367 times.
✓ Branch 6 taken 123 times.
✓ Branch 7 taken 15547461 times.
15547570 if (!error && all && xid_state->has_state(XID_STATE::XA_IDLE)) {
1741
3/6
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 123 times.
✗ Branch 5 not taken.
123 assert(
1742 thd->lex->sql_command == SQLCOM_XA_COMMIT &&
1743 static_cast<Sql_cmd_xa_commit *>(thd->lex->m_sql_cmd)->get_xa_opt() ==
1744 XA_ONE_PHASE);
1745
1746 123 xid_state->set_state(XID_STATE::XA_PREPARED);
1747 }
1748
1749 #ifdef WITH_WSREP
1750
3/4
✓ Branch 0 taken 13197875 times.
✓ Branch 1 taken 2349578 times.
✓ Branch 2 taken 13198505 times.
✗ Branch 3 not taken.
15547584 DEBUG_SYNC(thd, "wsrep_before_commit");
1751 #endif
1752
1753
7/8
✓ Branch 0 taken 15547384 times.
✓ Branch 1 taken 699 times.
✓ Branch 2 taken 15545498 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 699 times.
✓ Branch 5 taken 15544799 times.
✓ Branch 6 taken 1398 times.
✓ Branch 7 taken 15544799 times.
15548083 if (error || (error = tc_log->commit(thd, all))) {
1754
1/2
✓ Branch 0 taken 1398 times.
✗ Branch 1 not taken.
1398 ha_rollback_trans(thd, all);
1755 1398 error = 1;
1756 1398 goto end;
1757 }
1758 /*
1759 Mark multi-statement (any autocommit mode) or single-statement
1760 (autocommit=1) transaction as rolled back
1761 */
1762 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
1763
4/4
✓ Branch 0 taken 7906284 times.
✓ Branch 1 taken 7638515 times.
✓ Branch 2 taken 4831896 times.
✓ Branch 3 taken 3074388 times.
15544799 if (is_real_trans && thd->m_transaction_psi != nullptr) {
1764
1/2
✓ Branch 0 taken 4831268 times.
✗ Branch 1 not taken.
4831896 MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
1765 4831268 thd->m_transaction_psi = nullptr;
1766 }
1767 #endif
1768
5/8
✓ Branch 0 taken 15544618 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 15544579 times.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
15544171 DBUG_EXECUTE_IF("crash_commit_after",
1769 if (!thd->is_operating_gtid_table_implicitly)
1770 DBUG_SUICIDE(););
1771 15544579 end:
1772
4/4
✓ Branch 0 taken 3021462 times.
✓ Branch 1 taken 12524520 times.
✓ Branch 2 taken 2906831 times.
✓ Branch 3 taken 114631 times.
15545982 if (release_mdl && mdl_request.ticket) {
1773 /*
1774 We do not always immediately release transactional locks
1775 after ha_commit_trans() (see uses of ha_enable_transaction()),
1776 thus we release the commit blocker lock as soon as it's
1777 not needed.
1778 */
1779
5/8
✓ Branch 0 taken 2906478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2906340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 113 times.
✓ Branch 5 taken 2906227 times.
✓ Branch 6 taken 113 times.
✗ Branch 7 not taken.
2906831 DBUG_PRINT("debug", ("Releasing MDL commit lock"));
1780
1/2
✓ Branch 0 taken 2907870 times.
✗ Branch 1 not taken.
2906340 thd->mdl_context.release_lock(mdl_request.ticket);
1781 }
1782
1783 #ifdef WITH_WSREP
1784 /*
1785 New galera flow now start transaction even for read-only transaction.
1786 This read-only transaction will not change any row so will get committed
1787 as an empty transaction
1788 */
1789
13/14
✓ Branch 0 taken 15546947 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 311856 times.
✓ Branch 3 taken 15235091 times.
✓ Branch 4 taken 171631 times.
✓ Branch 5 taken 140225 times.
✓ Branch 6 taken 171415 times.
✓ Branch 7 taken 216 times.
✓ Branch 8 taken 72449 times.
✓ Branch 9 taken 98966 times.
✓ Branch 10 taken 72429 times.
✓ Branch 11 taken 7 times.
✓ Branch 12 taken 72441 times.
✓ Branch 13 taken 15474493 times.
15619457 if (wsrep_is_active(thd) && is_real_trans && !error && (rw_ha_count == 0) &&
1790 72449 wsrep_not_committed(thd)) {
1791
1/2
✓ Branch 0 taken 72236 times.
✗ Branch 1 not taken.
72441 wsrep_commit_empty(thd, all);
1792 }
1793 #endif /* WITH_WSREP */
1794
1795 /* Free resources and perform other cleanup even for 'empty' transactions. */
1796
2/2
✓ Branch 0 taken 7908423 times.
✓ Branch 1 taken 7638306 times.
15546729 if (is_real_trans) {
1797
1/2
✓ Branch 0 taken 7908813 times.
✗ Branch 1 not taken.
7908423 trn_ctx->cleanup();
1798 7908813 thd->tx_priority = 0;
1799 }
1800
1801
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 15546975 times.
15547119 if (need_clear_owned_gtid) {
1802 144 thd->server_status &= ~SERVER_STATUS_IN_TRANS;
1803 /*
1804 Release the owned GTID when binlog is disabled, or binlog is
1805 enabled and log_replica_updates is disabled with slave SQL thread
1806 or slave worker thread.
1807 */
1808
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 139 times.
144 if (error)
1809
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 gtid_state->update_on_rollback(thd);
1810 else
1811
1/2
✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
139 gtid_state->update_on_commit(thd);
1812 } else {
1813
7/8
✓ Branch 0 taken 15546686 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1052369 times.
✓ Branch 3 taken 14494317 times.
✓ Branch 4 taken 159 times.
✓ Branch 5 taken 1052210 times.
✓ Branch 6 taken 159 times.
✓ Branch 7 taken 15546527 times.
15546975 if (has_commit_order_manager(thd) && error) {
1814
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
159 gtid_state->update_on_rollback(thd);
1815 }
1816 }
1817
2/2
✓ Branch 0 taken 24143 times.
✓ Branch 1 taken 15522527 times.
15546670 if (run_slave_post_commit) {
1818
4/6
✓ Branch 0 taken 24143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 24087 times.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
24143 DBUG_EXECUTE_IF("replica_crash_after_commit", DBUG_SUICIDE(););
1819
1820
1/2
✓ Branch 0 taken 24087 times.
✗ Branch 1 not taken.
24087 thd->rli_slave->post_commit(error != 0);
1821 /*
1822 SERVER_STATUS_IN_TRANS may've been gained by pre_commit alone
1823 when the main DDL transaction is filtered out of execution.
1824 In such case the status has to be reset now.
1825
1826 TODO: move/refactor this handling onto trans_commit/commit_implicit()
1827 the caller level.
1828 */
1829 24087 thd->server_status &= ~SERVER_STATUS_IN_TRANS;
1830 } else {
1831
17/22
✓ Branch 0 taken 15522657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3508 times.
✓ Branch 3 taken 15519149 times.
✓ Branch 4 taken 1762 times.
✓ Branch 5 taken 1746 times.
✓ Branch 6 taken 1762 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 211 times.
✓ Branch 9 taken 1551 times.
✓ Branch 10 taken 7 times.
✓ Branch 11 taken 204 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 6 times.
✓ Branch 14 taken 1 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1 times.
✓ Branch 19 taken 3507 times.
✓ Branch 20 taken 1 times.
✗ Branch 21 not taken.
15522527 DBUG_EXECUTE_IF("replica_crash_after_commit", {
1832 if (thd->slave_thread && thd->rli_slave &&
1833 thd->rli_slave->current_event &&
1834 thd->rli_slave->current_event->get_type_code() ==
1835 binary_log::XID_EVENT &&
1836 !thd->is_operating_substatement_implicitly &&
1837 !thd->is_operating_gtid_table_implicitly && !transaction_to_skip)
1838 DBUG_SUICIDE();
1839 });
1840 }
1841
1842
2/2
✓ Branch 0 taken 15545021 times.
✓ Branch 1 taken 1722 times.
15546743 if (!error) thd->diff_commit_trans++;
1843
1844 15546743 return error;
1845 15546744 }
1846
1847 /**
1848 Commit the sessions outstanding transaction.
1849
1850 @pre thd->transaction.flags.commit_low == true
1851 @post thd->transaction.flags.commit_low == false
1852
1853 @note This function does not care about global read lock; the caller
1854 should.
1855
1856 @param[in] thd Thread handle.
1857 @param[in] all Is set in case of explicit commit
1858 (COMMIT statement), or implicit commit
1859 issued by DDL. Is not set when called
1860 at the end of statement, even if
1861 autocommit=1.
1862 @param[in] run_after_commit
1863 True by default, otherwise, does not execute
1864 the after_commit hook in the function.
1865 */
1866
1867 26412910 int ha_commit_low(THD *thd, bool all, bool run_after_commit) {
1868 26412910 int error = 0;
1869 26412910 Transaction_ctx *trn_ctx = thd->get_transaction();
1870 26413543 Transaction_ctx::enum_trx_scope trx_scope =
1871
2/2
✓ Branch 0 taken 6014804 times.
✓ Branch 1 taken 20398739 times.
26413543 all ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
1872
1/2
✓ Branch 0 taken 26412879 times.
✗ Branch 1 not taken.
26413543 auto ha_list = trn_ctx->ha_trx_info(trx_scope);
1873
1874
1/2
✓ Branch 0 taken 26415341 times.
✗ Branch 1 not taken.
26412879 DBUG_TRACE;
1875
1876 #ifdef WITH_WSREP
1877
5/8
✓ Branch 0 taken 52098 times.
✓ Branch 1 taken 26363243 times.
✓ Branch 2 taken 52098 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 52098 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 26415341 times.
26415341 if (thd->run_wsrep_commit_hooks && wsrep_before_commit(thd, all)) {
1878 thd->run_wsrep_commit_hooks = false;
1879 return 1;
1880 }
1881 #endif /* WITH_WSREP */
1882
1883
3/4
✓ Branch 0 taken 26415133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13616222 times.
✓ Branch 3 taken 12798911 times.
26415341 if (ha_list) {
1884 12798911 bool restore_backup_ha_data = false;
1885 /*
1886 At execution of XA COMMIT ONE PHASE binlog or slave applier
1887 reattaches the engine ha_data to THD, previously saved at XA START.
1888 */
1889
7/8
✓ Branch 0 taken 1233417 times.
✓ Branch 1 taken 11565494 times.
✓ Branch 2 taken 1233403 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 55 times.
✓ Branch 5 taken 1233348 times.
✓ Branch 6 taken 55 times.
✓ Branch 7 taken 12798842 times.
12798911 if (all && thd->is_engine_ha_data_detached()) {
1890
3/10
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 55 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
55 DBUG_PRINT("info", ("query='%s'", thd->query().str));
1891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 assert(thd->lex->sql_command == SQLCOM_XA_COMMIT);
1892
2/4
✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
55 assert(
1893 static_cast<Sql_cmd_xa_commit *>(thd->lex->m_sql_cmd)->get_xa_opt() ==
1894 XA_ONE_PHASE);
1895 55 restore_backup_ha_data = true;
1896 }
1897
1898 12798897 bool is_applier_wait_enabled = false;
1899
1900 /*
1901 Preserve externalization and persistence order for applier threads.
1902
1903 The conditions should be understood as follows:
1904
1905 - When the binlog is enabled, this will be done from
1906 MYSQL_BIN_LOG::ordered_commit and should not be done here.
1907 Therefore, we have the condition
1908 thd->is_current_stmt_binlog_disabled().
1909
1910 - This function is usually called once per statement, with
1911 all=false. We should not preserve the commit order when this
1912 function is called in that context. Therefore, we have the
1913 condition ending_trans(thd, all).
1914
1915 - Statements such as ANALYZE/OPTIMIZE/REPAIR TABLE will call
1916 ha_commit_low multiple times with all=true from within
1917 mysql_admin_table, mysql_recreate_table, and
1918 handle_histogram_command. After returning to
1919 mysql_execute_command, it will call ha_commit_low one last
1920 time. It is only in this final call that we should preserve
1921 the commit order. Therefore, we set the flag
1922 thd->is_operating_substatement_implicitly while executing
1923 mysql_admin_table, mysql_recreate_table, and
1924 handle_histogram_command, clear it when returning from those
1925 functions, and check the flag here in ha_commit_low().
1926
1927 - In all the above cases, we should make the current transaction
1928 fail early in case a previous transaction has rolled back.
1929 Therefore, we also invoke the commit order manager in case
1930 get_rollback_status returns true.
1931
1932 Note: the calls to Commit_order_manager::wait/wait_and_finish() will be
1933 no-op for threads other than replication applier threads.
1934 */
1935 37399212 if ((!thd->is_operating_substatement_implicitly &&
1936
2/2
✓ Branch 0 taken 11637228 times.
✓ Branch 1 taken 164202 times.
11801430 !thd->is_operating_gtid_table_implicitly &&
1937
3/4
✓ Branch 0 taken 11637256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4237982 times.
✓ Branch 3 taken 7399274 times.
11637228 thd->is_current_stmt_binlog_log_replica_updates_disabled() &&
1938
7/8
✓ Branch 0 taken 11801430 times.
✓ Branch 1 taken 997467 times.
✓ Branch 2 taken 4237982 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3885348 times.
✓ Branch 5 taken 352634 times.
✓ Branch 6 taken 352701 times.
✓ Branch 7 taken 12446184 times.
29483130 ending_trans(thd, all)) ||
1939
3/4
✓ Branch 0 taken 12446251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 12446184 times.
12446291 Commit_order_manager::get_rollback_status(thd)) {
1940
3/4
✓ Branch 0 taken 352701 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 352631 times.
352701 if (Commit_order_manager::wait(thd)) {
1941 70 error = 1;
1942 /*
1943 Remove applier thread from waiting in Commit Order Queue and
1944 allow next applier thread to be ordered.
1945 */
1946
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 Commit_order_manager::wait_and_finish(thd, error);
1947 70 goto err;
1948 }
1949 352631 is_applier_wait_enabled = true;
1950 }
1951
1952
7/12
✓ Branch 0 taken 12798845 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12798856 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17777075 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17776834 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30575666 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 17777067 times.
✓ Branch 11 taken 12798599 times.
30575878 for (auto &ha_info : ha_list) {
1953 int err;
1954 17777075 auto ht = ha_info.ht();
1955
3/4
✓ Branch 0 taken 17776919 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 17776915 times.
17777085 if ((err = ht->commit(ht, thd, all))) {
1956 char errbuf[MYSQL_ERRMSG_SIZE];
1957
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err,
1958 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
1959 4 error = 1;
1960 }
1961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17776919 times.
17776919 assert(!thd->status_var_aggregated);
1962 17776919 thd->status_var.ha_commit_count++;
1963
1/2
✓ Branch 0 taken 17777063 times.
✗ Branch 1 not taken.
17776919 ha_info.reset(); /* keep it conveniently zero-filled */
1964 12798599 }
1965
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12798545 times.
✓ Branch 2 taken 55 times.
✗ Branch 3 not taken.
12798600 if (restore_backup_ha_data) thd->rpl_reattach_engine_ha_data();
1966
1/2
✓ Branch 0 taken 12798791 times.
✗ Branch 1 not taken.
12798600 trn_ctx->reset_scope(trx_scope);
1967
1968 /*
1969 After ensuring externalization order for applier thread, remove it
1970 from waiting (Commit Order Queue) and allow next applier thread to
1971 be ordered.
1972
1973 Note: the calls to Commit_order_manager::wait_and_finish() will be
1974 no-op for threads other than replication applier threads.
1975 */
1976
2/2
✓ Branch 0 taken 352630 times.
✓ Branch 1 taken 12446161 times.
12798791 if (is_applier_wait_enabled) {
1977
1/2
✓ Branch 0 taken 352621 times.
✗ Branch 1 not taken.
352630 Commit_order_manager::wait_and_finish(thd, error);
1978 }
1979 }
1980
1981 13616222 err:
1982 /* Free resources and perform other cleanup even for 'empty' transactions. */
1983
3/4
✓ Branch 0 taken 6015007 times.
✓ Branch 1 taken 20400067 times.
✓ Branch 2 taken 6015003 times.
✗ Branch 3 not taken.
26415074 if (all) trn_ctx->cleanup();
1984 /*
1985 When the transaction has been committed, we clear the commit_low
1986 flag. This allow other parts of the system to check if commit_low
1987 was called.
1988 */
1989 26415070 trn_ctx->m_flags.commit_low = false;
1990
6/6
✓ Branch 0 taken 23831754 times.
✓ Branch 1 taken 2583316 times.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 23831548 times.
✓ Branch 4 taken 83 times.
✓ Branch 5 taken 26414864 times.
26415070 if (run_after_commit && thd->get_transaction()->m_flags.run_hooks) {
1991 /*
1992 If commit succeeded, we call the after_commit hook.
1993
1994 TODO: Investigate if this can be refactored so that there is
1995 only one invocation of this hook in the code (in
1996 MYSQL_LOG_BIN::finish_commit).
1997 */
1998
3/8
✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 83 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
83 if (!error) (void)RUN_HOOK(transaction, after_commit, (thd, all));
1999 83 trn_ctx->m_flags.run_hooks = false;
2000 }
2001
2002 #ifdef WITH_WSREP
2003
4/4
✓ Branch 0 taken 26414702 times.
✓ Branch 1 taken 245 times.
✓ Branch 2 taken 52098 times.
✓ Branch 3 taken 26362604 times.
26414947 if (!error && thd->run_wsrep_commit_hooks) {
2004
1/2
✓ Branch 0 taken 52015 times.
✗ Branch 1 not taken.
52098 (void)wsrep_after_commit(thd, all);
2005 }
2006 26414864 thd->run_wsrep_commit_hooks = false;
2007 #endif /* WITH_WSREP */
2008
2009 26414864 return error;
2010 26414864 }
2011
2012 2105898 int ha_rollback_low(THD *thd, bool all) {
2013 2105898 Transaction_ctx *trn_ctx = thd->get_transaction();
2014 2106237 int error = 0;
2015 2106237 Transaction_ctx::enum_trx_scope trx_scope =
2016
2/2
✓ Branch 0 taken 1193719 times.
✓ Branch 1 taken 912518 times.
2106237 all ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
2017
1/2
✓ Branch 0 taken 2105661 times.
✗ Branch 1 not taken.
2106237 auto ha_list = trn_ctx->ha_trx_info(trx_scope);
2018
2019
4/6
✓ Branch 0 taken 2105046 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 336905 times.
✓ Branch 3 taken 1768141 times.
✓ Branch 4 taken 337524 times.
✗ Branch 5 not taken.
2105661 (void)RUN_HOOK(transaction, before_rollback, (thd, all));
2020
2021 #ifdef WITH_WSREP
2022
1/2
✓ Branch 0 taken 2107249 times.
✗ Branch 1 not taken.
2105665 (void)wsrep_before_rollback(thd, all);
2023 #endif /* WITH_WSREP */
2024
2025
3/4
✓ Branch 0 taken 2107055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647414 times.
✓ Branch 3 taken 1459641 times.
2107249 if (ha_list) {
2026 647414 bool restore_backup_ha_data = false;
2027 /*
2028 Similarly to the commit case, the binlog or slave applier
2029 reattaches the engine ha_data to THD.
2030 */
2031
7/8
✓ Branch 0 taken 10480 times.
✓ Branch 1 taken 636934 times.
✓ Branch 2 taken 10481 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 10460 times.
✓ Branch 6 taken 21 times.
✓ Branch 7 taken 647394 times.
647414 if (all && thd->is_engine_ha_data_detached()) {
2032
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
21 assert(trn_ctx->xid_state()->get_state() != XID_STATE::XA_NOTR ||
2033 thd->killed == THD::KILL_CONNECTION);
2034
2035 21 restore_backup_ha_data = true;
2036 }
2037
2038
7/12
✓ Branch 0 taken 647416 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647416 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 654610 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 654602 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1302014 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 654610 times.
✓ Branch 11 taken 647404 times.
1302018 for (auto &ha_info : ha_list) {
2039 int err;
2040 654610 auto ht = ha_info.ht();
2041
2/4
✓ Branch 0 taken 654600 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 654600 times.
654614 if ((err = ht->rollback(ht, thd, all))) { // cannot happen
2042
2043 #ifdef WITH_WSREP
2044 WSREP_INFO(
2045 "rollback failed for handlerton: %d, conflict-state: %s SQL %s",
2046 ht->db_type, wsrep_thd_transaction_state_str(thd),
2047 thd->query().str);
2048 Diagnostics_area *da = thd->get_stmt_da();
2049 if (da) {
2050 WSREP_INFO("stmt DA %d %s", da->status(),
2051 (da->is_error()) ? da->message_text() : "void");
2052 }
2053 #endif /* WITH_WSREP */
2054
2055 char errbuf[MYSQL_ERRMSG_SIZE];
2056 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err,
2057 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2058 error = 1;
2059 }
2060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 654600 times.
654600 assert(!thd->status_var_aggregated);
2061 654600 thd->status_var.ha_rollback_count++;
2062
1/2
✓ Branch 0 taken 654603 times.
✗ Branch 1 not taken.
654600 ha_info.reset(); /* keep it conveniently zero-filled */
2063 647404 }
2064
3/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 647383 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
647404 if (restore_backup_ha_data) thd->rpl_reattach_engine_ha_data();
2065
1/2
✓ Branch 0 taken 647181 times.
✗ Branch 1 not taken.
647404 trn_ctx->reset_scope(trx_scope);
2066 }
2067
2068 /*
2069 Thanks to possibility of MDL deadlock rollback request can come even if
2070 transaction hasn't been started in any transactional storage engine.
2071
2072 It is possible to have a call of ha_rollback_low() while handling
2073 failure from Sql_cmd_xa_prepare::process_xa_prepare() and an error in
2074 Daignostics_area still wasn't set. Therefore it is required to check
2075 that an error in Diagnostics_area is set before calling the method
2076 XID_STATE::set_error().
2077
2078 If it wasn't done it would lead to failure of the assertion
2079 assert(m_status == DA_ERROR)
2080 in the method Diagnostics_area::mysql_errno().
2081
2082 In case Sql_cmd_xa_prepare::process_xa_prepare() has failed and an error
2083 wasn't set in Diagnostics_area the error ER_XA_RBROLLBACK is set in the
2084 Diagnostics_area from the method Sql_cmd_xa_prepare::trans_xa_prepare()
2085 when non-zero result code returned by
2086 Sql_cmd_xa_prepare::process_xa_prepare() is handled.
2087 */
2088
9/10
✓ Branch 0 taken 1193851 times.
✓ Branch 1 taken 912971 times.
✓ Branch 2 taken 512 times.
✓ Branch 3 taken 1193339 times.
✓ Branch 4 taken 512 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 508 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 508 times.
✓ Branch 9 taken 2106314 times.
2106822 if (all && thd->transaction_rollback_request && thd->is_error())
2089
1/2
✓ Branch 0 taken 508 times.
✗ Branch 1 not taken.
508 trn_ctx->xid_state()->set_error(thd);
2090
2091 #ifdef WITH_WSREP
2092
3/4
✓ Branch 0 taken 2107483 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 251624 times.
✓ Branch 3 taken 1855859 times.
2106822 if (thd->is_error()) {
2093
23/42
✓ Branch 0 taken 1831 times.
✓ Branch 1 taken 249793 times.
✓ Branch 2 taken 1831 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1831 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1831 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1831 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1831 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1831 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 1831 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 1831 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 1831 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 1831 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 3 times.
✓ Branch 23 taken 1828 times.
✓ Branch 24 taken 3 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 3 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 1828 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 7 times.
✓ Branch 31 taken 1824 times.
✓ Branch 32 taken 1831 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 3 times.
✓ Branch 35 taken 1828 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 1831 times.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
251624 WSREP_DEBUG("ha_rollback_trans(%u, %s) rolled back: %s: XX%s;",
2094 thd->thread_id(), all ? "TRUE" : "FALSE", WSREP_QUERY(thd),
2095 thd->get_stmt_da()->message_text());
2096
9/10
✓ Branch 0 taken 251618 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 46221 times.
✓ Branch 3 taken 205397 times.
✓ Branch 4 taken 11112 times.
✓ Branch 5 taken 35109 times.
✓ Branch 6 taken 10198 times.
✓ Branch 7 taken 914 times.
✓ Branch 8 taken 10198 times.
✗ Branch 9 not taken.
251624 WSREP_NBO_1ST_PHASE_END;
2097 }
2098
1/2
✓ Branch 0 taken 2106661 times.
✗ Branch 1 not taken.
2107483 (void)wsrep_after_rollback(thd, all);
2099 #endif /* WITH_WSREP */
2100
2101
4/6
✓ Branch 0 taken 2106774 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 337437 times.
✓ Branch 3 taken 1769337 times.
✓ Branch 4 taken 337560 times.
✗ Branch 5 not taken.
2106661 (void)RUN_HOOK(transaction, after_rollback, (thd, all));
2102 2106112 return error;
2103 2106897 }
2104
2105 1869534 int ha_rollback_trans(THD *thd, bool all) {
2106 1869534 int error = 0;
2107 1869534 Transaction_ctx *trn_ctx = thd->get_transaction();
2108 1870085 bool is_xa_rollback = trn_ctx->xid_state()->has_state(XID_STATE::XA_PREPARED);
2109
2110 /*
2111 "real" is a nick name for a transaction for which a commit will
2112 make persistent changes. E.g. a 'stmt' transaction inside a 'all'
2113 transaction is not 'real': even though it's possible to commit it,
2114 the changes are not durable as they might be rolled back if the
2115 enclosing 'all' transaction is rolled back.
2116 We establish the value of 'is_real_trans' by checking
2117 if it's an explicit COMMIT or BEGIN statement, or implicit
2118 commit issued by DDL (in these cases all == true),
2119 or if we're running in autocommit mode (it's only in the autocommit mode
2120 ha_commit_one_phase() is called with an empty
2121 transaction.all.ha_list, see why in trans_register_ha()).
2122 */
2123
4/4
✓ Branch 0 taken 636941 times.
✓ Branch 1 taken 1233183 times.
✓ Branch 2 taken 629450 times.
✓ Branch 3 taken 7491 times.
1870124 bool is_real_trans = all || !trn_ctx->is_active(Transaction_ctx::SESSION);
2124
2125
1/2
✓ Branch 0 taken 1870304 times.
✗ Branch 1 not taken.
1870124 DBUG_TRACE;
2126
2127 /*
2128 We must not rollback the normal transaction if a statement
2129 transaction is pending.
2130 */
2131
3/4
✓ Branch 0 taken 636092 times.
✓ Branch 1 taken 1234480 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 636092 times.
1870304 assert(!trn_ctx->is_active(Transaction_ctx::STMT) || !all);
2132
2133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1870572 times.
1870572 if (thd->in_sub_stmt) {
2134 assert(0);
2135 /*
2136 If we are inside stored function or trigger we should not commit or
2137 rollback current statement transaction. See comment in ha_commit_trans()
2138 call for more information.
2139 */
2140 if (!all) return 0;
2141 my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
2142 return 1;
2143 }
2144
2145
3/4
✓ Branch 0 taken 1831474 times.
✓ Branch 1 taken 39098 times.
✓ Branch 2 taken 1830997 times.
✗ Branch 3 not taken.
1870572 if (tc_log) error = tc_log->rollback(thd, all);
2146 /*
2147 Mark multi-statement (any autocommit mode) or single-statement
2148 (autocommit=1) transaction as rolled back
2149 */
2150 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
2151
6/6
✓ Branch 0 taken 636942 times.
✓ Branch 1 taken 1233153 times.
✓ Branch 2 taken 629239 times.
✓ Branch 3 taken 7703 times.
✓ Branch 4 taken 1862522 times.
✓ Branch 5 taken 7573 times.
1870095 if (all || !thd->in_active_multi_stmt_transaction()) {
2152
1/2
✓ Branch 0 taken 1862383 times.
✗ Branch 1 not taken.
1862522 MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi);
2153 1862383 thd->m_transaction_psi = nullptr;
2154 }
2155 #endif
2156
2157 1869956 thd->diff_rollback_trans++;
2158
2159 /* Always cleanup. Even if nht==0. There may be savepoints. */
2160
2/2
✓ Branch 0 taken 1862848 times.
✓ Branch 1 taken 7108 times.
1869956 if (is_real_trans) {
2161
1/2
✓ Branch 0 taken 1862875 times.
✗ Branch 1 not taken.
1862848 trn_ctx->cleanup();
2162 1862875 thd->tx_priority = 0;
2163 }
2164
2165
2/2
✓ Branch 0 taken 1233395 times.
✓ Branch 1 taken 636588 times.
1869983 if (all) thd->transaction_rollback_request = false;
2166
2167 /*
2168 Only call gtid_rollback(THD*), which will purge thd->owned_gtid, if
2169 complete transaction is being rollback or autocommit=1.
2170 Notice, XA rollback has just invoked update_on_commit() through
2171 tc_log->*rollback* stack.
2172 */
2173
4/6
✓ Branch 0 taken 1862918 times.
✓ Branch 1 taken 7065 times.
✓ Branch 2 taken 1862986 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1863420 times.
✗ Branch 5 not taken.
1869983 if (is_real_trans && !is_xa_rollback) gtid_state->update_on_rollback(thd);
2174
2175 /*
2176 If the transaction cannot be rolled back safely, warn; don't warn if this
2177 is a slave thread (because when a slave thread executes a ROLLBACK, it has
2178 been read from the binary log, so it's 100% sure and normal to produce
2179 error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
2180 slave SQL thread, it would not stop the thread but just be printed in
2181 the error log; but we don't want users to wonder why they have this
2182 message in the error log, so we don't send it.
2183 */
2184
2/2
✓ Branch 0 taken 3531 times.
✓ Branch 1 taken 1859501 times.
1863032 if (is_real_trans &&
2185 1863205 trn_ctx->cannot_safely_rollback(Transaction_ctx::SESSION) &&
2186
8/8
✓ Branch 0 taken 1863205 times.
✓ Branch 1 taken 7212 times.
✓ Branch 2 taken 3344 times.
✓ Branch 3 taken 187 times.
✓ Branch 4 taken 2834 times.
✓ Branch 5 taken 510 times.
✓ Branch 6 taken 2834 times.
✓ Branch 7 taken 1867410 times.
3733449 !thd->slave_thread && thd->killed != THD::KILL_CONNECTION)
2187
1/2
✓ Branch 0 taken 2834 times.
✗ Branch 1 not taken.
2834 trn_ctx->push_unsafe_rollback_warnings(thd);
2188
2189 1870244 return error;
2190 1870244 }
2191
2192 /**
2193 Commit the attachable transaction in storage engines.
2194
2195 @note This is slimmed down version of ha_commit_trans()/ha_commit_low()
2196 which commits attachable transaction but skips code which is
2197 unnecessary and unsafe for them (like dealing with GTIDs).
2198 Since attachable transactions are read-only their commit only
2199 needs to release resources and cleanup state in SE.
2200
2201 @param thd Current thread
2202
2203 @retval 0 - Success
2204 @retval non-0 - Failure
2205 */
2206 15218298 int ha_commit_attachable(THD *thd) {
2207 15218298 int error = 0;
2208 15218298 Transaction_ctx *trn_ctx = thd->get_transaction();
2209
1/2
✓ Branch 0 taken 15218314 times.
✗ Branch 1 not taken.
15218318 auto ha_list = trn_ctx->ha_trx_info(Transaction_ctx::STMT);
2210
2211 /* This function only handles attachable transactions. */
2212
2/4
✓ Branch 0 taken 15218325 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15218325 times.
15218314 assert(thd->is_attachable_ro_transaction_active());
2213 /*
2214 Since the attachable transaction is AUTOCOMMIT we only need
2215 to care about statement transaction.
2216 */
2217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15218325 times.
15218325 assert(!trn_ctx->is_active(Transaction_ctx::SESSION));
2218
2219
2/4
✓ Branch 0 taken 15218307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15218310 times.
✗ Branch 3 not taken.
15218325 if (ha_list) {
2220
7/12
✓ Branch 0 taken 15218323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15218326 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15218300 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15218327 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 30436623 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 15218301 times.
✓ Branch 11 taken 15218322 times.
30436639 for (auto &ha_info : ha_list) {
2221 /* Attachable transaction is not supposed to modify anything. */
2222
2/4
✓ Branch 0 taken 15218321 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15218321 times.
15218300 assert(!ha_info.is_trx_read_write());
2223
2224 15218321 auto ht = ha_info.ht();
2225
2/4
✓ Branch 0 taken 15218325 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15218325 times.
15218326 if (ht->commit(ht, thd, false)) {
2226 /*
2227 In theory this should not happen since attachable transactions
2228 are read only and therefore commit is supposed to only release
2229 resources/cleanup state. Even if this happens we will simply
2230 continue committing attachable transaction in other SEs.
2231 */
2232 assert(false);
2233 error = 1;
2234 }
2235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15218325 times.
15218325 assert(!thd->status_var_aggregated);
2236 15218325 thd->status_var.ha_commit_count++;
2237
1/2
✓ Branch 0 taken 15218329 times.
✗ Branch 1 not taken.
15218325 ha_info.reset(); /* keep it conveniently zero-filled */
2238 15218322 }
2239
1/2
✓ Branch 0 taken 15218333 times.
✗ Branch 1 not taken.
15218315 trn_ctx->reset_scope(Transaction_ctx::STMT);
2240 }
2241
2242 /*
2243 Mark transaction as committed in PSI.
2244 */
2245 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
2246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15218330 times.
15218330 if (thd->m_transaction_psi != nullptr) {
2247 MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
2248 thd->m_transaction_psi = nullptr;
2249 }
2250 #endif
2251
2252 /* Free resources and perform other cleanup even for 'empty' transactions. */
2253
1/2
✓ Branch 0 taken 15218328 times.
✗ Branch 1 not taken.
15218330 trn_ctx->cleanup();
2254
2255 15218326 return (error);
2256 15218328 }
2257
2258 /**
2259 Check if all storage engines used in transaction agree that after
2260 rollback to savepoint it is safe to release MDL locks acquired after
2261 savepoint creation.
2262
2263 @param thd The client thread that executes the transaction.
2264
2265 @return true - It is safe to release MDL locks.
2266 false - If it is not.
2267 */
2268 4265 bool ha_rollback_to_savepoint_can_release_mdl(THD *thd) {
2269 4265 Transaction_ctx *trn_ctx = thd->get_transaction();
2270 4265 Transaction_ctx::enum_trx_scope trx_scope =
2271 4265 thd->in_sub_stmt ? Transaction_ctx::STMT : Transaction_ctx::SESSION;
2272
2273
1/2
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
4265 DBUG_TRACE;
2274
2275 /**
2276 Checking whether it is safe to release metadata locks after rollback to
2277 savepoint in all the storage engines that are part of the transaction.
2278 */
2279
8/14
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4265 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4265 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8250 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4227 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8492 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 8250 times.
✓ Branch 13 taken 242 times.
8492 for (auto const &ha_info : trn_ctx->ha_trx_info(trx_scope)) {
2280 8250 auto ht = ha_info.ht();
2281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8250 times.
8250 assert(ht);
2282
2283
3/4
✓ Branch 0 taken 8250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4023 times.
✓ Branch 3 taken 4227 times.
16500 if (ht->savepoint_rollback_can_release_mdl == nullptr ||
2284
3/4
✓ Branch 0 taken 8250 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4023 times.
✓ Branch 3 taken 4227 times.
8250 ht->savepoint_rollback_can_release_mdl(ht, thd) == false)
2285 4023 return false;
2286
6/6
✓ Branch 0 taken 242 times.
✓ Branch 1 taken 4023 times.
✓ Branch 2 taken 242 times.
✓ Branch 3 taken 4023 times.
✓ Branch 4 taken 242 times.
✓ Branch 5 taken 4023 times.
12311 }
2287
2288 242 return true;
2289 4265 }
2290
2291 4265 int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv) {
2292 4265 int error = 0;
2293 4265 Transaction_ctx *trn_ctx = thd->get_transaction();
2294 4265 Transaction_ctx::enum_trx_scope trx_scope =
2295
2/2
✓ Branch 0 taken 4228 times.
✓ Branch 1 taken 37 times.
4265 !thd->in_sub_stmt ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
2296
2297
1/2
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
4265 DBUG_TRACE;
2298
2299 4265 trn_ctx->set_rw_ha_count(trx_scope, 0);
2300 4265 trn_ctx->set_no_2pc(trx_scope, false);
2301 /*
2302 rolling back to savepoint in all storage engines that were part of the
2303 transaction when the savepoint was set
2304 */
2305
1/2
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
4265 Ha_trx_info_list ha_list{sv->ha_list};
2306
7/12
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4265 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8272 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8272 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12537 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8272 times.
✓ Branch 11 taken 4265 times.
12537 for (auto const &ha_info : ha_list) {
2307 int err;
2308 8272 auto ht = ha_info.ht();
2309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
8272 assert(ht);
2310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
8272 assert(ht->savepoint_set != nullptr);
2311
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
8272 if ((err = ht->savepoint_rollback(
2312 ht, thd,
2313
1/2
✓ Branch 0 taken 8272 times.
✗ Branch 1 not taken.
8272 (uchar *)(sv + 1) + ht->savepoint_offset))) { // cannot happen
2314 char errbuf[MYSQL_ERRMSG_SIZE];
2315 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err,
2316 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2317 error = 1;
2318 }
2319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
8272 assert(!thd->status_var_aggregated);
2320 8272 thd->status_var.ha_savepoint_rollback_count++;
2321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8272 times.
8272 if (ht->prepare == nullptr) trn_ctx->set_no_2pc(trx_scope, true);
2322 4265 }
2323
2324 /*
2325 rolling back the transaction in all storage engines that were not part of
2326 the transaction when the savepoint was set
2327 */
2328
2/4
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4265 times.
✗ Branch 3 not taken.
4265 ha_list = trn_ctx->ha_trx_info(trx_scope);
2329
5/8
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4335 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 70 times.
✓ Branch 7 taken 4265 times.
4335 for (auto ha_info = ha_list.begin(); ha_info != sv->ha_list; ++ha_info) {
2330 int err;
2331
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 auto *ht = ha_info->ht();
2332
2333 #ifdef WITH_WSREP
2334
7/10
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 62 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4 times.
70 if (WSREP(thd) && (ht->flags & HTON_WSREP_REPLICATION)) {
2335
1/24
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
4 WSREP_DEBUG(
2336 "ha_rollback_to_savepoint: run before_rollback"
2337 " ha_rollback_trans hook");
2338
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 (void)wsrep_before_rollback(thd, !thd->in_sub_stmt);
2339 }
2340 #endif /* WITH_WSREP */
2341
2342
2/4
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
70 if ((err = ht->rollback(ht, thd, !thd->in_sub_stmt))) { // cannot happen
2343 char errbuf[MYSQL_ERRMSG_SIZE];
2344 my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err,
2345 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2346 error = 1;
2347 }
2348
2349 #ifdef WITH_WSREP
2350
7/10
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 62 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✓ Branch 9 taken 4 times.
70 if (WSREP(thd) && (ht->flags & HTON_WSREP_REPLICATION)) {
2351
1/24
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
4 WSREP_DEBUG("ha_rollback_to_savepoint: run after_rollback hook");
2352
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 (void)wsrep_after_rollback(thd, !thd->in_sub_stmt);
2353
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (thd->wsrep_trx().bf_aborted()) {
2354 1 thd->wsrep_cs().mark_force_bf_abort();
2355 }
2356 }
2357 #endif /* WITH_WSREP */
2358
2359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 assert(!thd->status_var_aggregated);
2360 70 thd->status_var.ha_rollback_count++;
2361
2/4
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
70 ha_info->reset(); /* keep it conveniently zero-filled */
2362 4265 }
2363
1/2
✓ Branch 0 taken 4265 times.
✗ Branch 1 not taken.
4265 trn_ctx->set_ha_trx_info(trx_scope, sv->ha_list);
2364
2365 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
2366
2/2
✓ Branch 0 taken 4264 times.
✓ Branch 1 taken 1 times.
4265 if (thd->m_transaction_psi != nullptr)
2367
1/2
✓ Branch 0 taken 4264 times.
✗ Branch 1 not taken.
4264 MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(thd->m_transaction_psi, 1);
2368 #endif
2369
2370 4265 thd->diff_rollback_trans++;
2371
2372 4265 return error;
2373 4265 }
2374
2375 4974222 int ha_prepare_low(THD *thd, bool all) {
2376
1/2
✓ Branch 0 taken 4974291 times.
✗ Branch 1 not taken.
4974222 DBUG_TRACE;
2377 4974291 int error = 0;
2378 4974291 Transaction_ctx::enum_trx_scope trx_scope =
2379
2/2
✓ Branch 0 taken 536782 times.
✓ Branch 1 taken 4437509 times.
4974291 all ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
2380
1/2
✓ Branch 0 taken 4974279 times.
✗ Branch 1 not taken.
4974291 auto ha_list = thd->get_transaction()->ha_trx_info(trx_scope);
2381
2382
2/4
✓ Branch 0 taken 4974288 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4974288 times.
✗ Branch 3 not taken.
4974279 if (ha_list) {
2383
7/12
✓ Branch 0 taken 4974296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4974290 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9948459 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9948361 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 14922594 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9948441 times.
✓ Branch 11 taken 4974153 times.
14922580 for (auto const &ha_info : ha_list) {
2384
4/6
✓ Branch 0 taken 9948499 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 9948489 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9948499 times.
9948469 if (!ha_info.is_trx_read_write() && // Do not call two-phase commit if
2385 // transaction is read-only
2386
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
10 !thd_holds_xa_transaction(thd)) // but only if is not an XA
2387 // transaction
2388 continue;
2389
2390 9948499 auto ht = ha_info.ht();
2391
2392 #ifdef WITH_WSREP
2393
1/2
✓ Branch 0 taken 9948497 times.
✗ Branch 1 not taken.
9948481 const bool run_wsrep_hooks = wsrep_run_commit_hook(thd, all);
2394 int err;
2395
2396
6/6
✓ Branch 0 taken 92950 times.
✓ Branch 1 taken 9855547 times.
✓ Branch 2 taken 46474 times.
✓ Branch 3 taken 46476 times.
✓ Branch 4 taken 202 times.
✓ Branch 5 taken 9948294 times.
9994970 if (run_wsrep_hooks && (ht->flags & HTON_WSREP_REPLICATION) &&
2397
3/4
✓ Branch 0 taken 46473 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 202 times.
✓ Branch 3 taken 46271 times.
46474 (err = wsrep_before_prepare(thd, all))) {
2398 // before prepare can fail during certify due to local certification
2399 // failure but it should get communicated as generic deadlock error.
2400
1/24
✗ Branch 0 not taken.
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
202 WSREP_DEBUG(
2401 "wsrep_before_prepare hook (replication + certification)"
2402 " failed to execute");
2403
1/2
✓ Branch 0 taken 202 times.
✗ Branch 1 not taken.
202 mysql_mutex_lock(&thd->LOCK_wsrep_thd);
2404 202 bool must_replay = wsrep_must_replay(thd);
2405
1/2
✓ Branch 0 taken 202 times.
✗ Branch 1 not taken.
202 mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
2406
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 76 times.
202 if (!must_replay) {
2407
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 2 times.
126 if (thd->wsrep_cs().current_error() == wsrep::e_size_exceeded_error) {
2408 // retain existing error code and message
2409 } else {
2410 /* set error only if transaction is not marked for replay. */
2411 char errbuf[MYSQL_ERRMSG_SIZE];
2412
2/4
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
✗ Branch 3 not taken.
124 my_error(ER_LOCK_DEADLOCK, MYF(0), err,
2413 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2414 }
2415 }
2416
2417 202 error = 1;
2418 202 continue;
2419 202 }
2420
2421 /* core-prepare logic is no more affected by the pxc error.
2422 pxc replication and certification is now take care above as part of
2423 wsrep_before_prepare. */
2424
1/2
✓ Branch 0 taken 9948218 times.
✗ Branch 1 not taken.
9948294 err = ht->prepare(ht, thd, all);
2425
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 9948096 times.
9948218 if (err) {
2426
3/4
✓ Branch 0 taken 122 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✓ Branch 3 taken 1 times.
122 if (!thd_holds_xa_transaction(
2427 thd)) { // If XA PREPARE, let error be handled by caller
2428 char errbuf[MYSQL_ERRMSG_SIZE];
2429
2/4
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
121 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err,
2430 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2431 }
2432 122 error = 1;
2433 }
2434
2435
8/8
✓ Branch 0 taken 92744 times.
✓ Branch 1 taken 9855474 times.
✓ Branch 2 taken 92743 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 46271 times.
✓ Branch 5 taken 46472 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 9948212 times.
9994489 if (run_wsrep_hooks && !error && (ht->flags & HTON_WSREP_REPLICATION) &&
2436
3/4
✓ Branch 0 taken 46271 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 46265 times.
46271 wsrep_after_prepare(thd, all)) {
2437
1/24
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
6 WSREP_DEBUG(
2438 "wsrep_after_prepare hook (replication + certification)"
2439 " failed to execute");
2440 char errbuf[MYSQL_ERRMSG_SIZE];
2441
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 my_error(ER_LOCK_DEADLOCK, MYF(0), err,
2442 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2443 6 error = 1;
2444 }
2445 #else
2446 int err = ht->prepare(ht, thd, all);
2447 if (err) {
2448 if (!thd_holds_xa_transaction(
2449 thd)) { // If XA PREPARE, let error be handled by caller
2450 char errbuf[MYSQL_ERRMSG_SIZE];
2451 my_error(ER_ERROR_DURING_COMMIT, MYF(0), err,
2452 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2453 }
2454 error = 1;
2455 }
2456 #endif /* WITH_WSREP */
2457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9948218 times.
9948218 assert(!thd->status_var_aggregated);
2458 9948218 thd->status_var.ha_prepare_count++;
2459
2460
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 9948090 times.
9948218 if (error) break;
2461 4974281 }
2462
4/6
✓ Branch 0 taken 4974292 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4974283 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
4974295 DBUG_EXECUTE_IF("crash_commit_after_prepare", DBUG_SUICIDE(););
2463 }
2464
2465 4974287 return error;
2466 4974283 }
2467
2468 /**
2469 @note
2470 according to the sql standard (ISO/IEC 9075-2:2003)
2471 section "4.33.4 SQL-statements and transaction states",
2472 SAVEPOINT is *not* transaction-initiating SQL-statement
2473 */
2474 8279 int ha_savepoint(THD *thd, SAVEPOINT *sv) {
2475 #if 0
2476 /* commenting it out for now.
2477 it was not present in 5.7. there is no reason explained why
2478 it was added in 8.x. out-of-order registering binlog handler
2479 for savepoint causes issues rolling back acting local trx
2480 executing rollback to savepoint when it is killed by high priority
2481 trx.
2482 */
2483 #ifdef WITH_WSREP
2484 /*
2485 Register binlog hton for savepoint processing if wsrep binlog
2486 emulation is on.
2487 */
2488 if (WSREP_EMULATE_BINLOG(thd) && wsrep_thd_is_local(thd)) {
2489 wsrep_register_binlog_handler(thd, thd->in_multi_stmt_transaction_mode());
2490 }
2491 #endif /* WITH_WSREP */
2492 #endif
2493
2494 8279 int error = 0;
2495 8279 Transaction_ctx::enum_trx_scope trx_scope =
2496
2/2
✓ Branch 0 taken 8190 times.
✓ Branch 1 taken 89 times.
8279 !thd->in_sub_stmt ? Transaction_ctx::SESSION : Transaction_ctx::STMT;
2497
2498
1/2
✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
8279 DBUG_TRACE;
2499
2500
1/2
✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
8279 auto ha_list = thd->get_transaction()->ha_trx_info(trx_scope);
2501
6/10
✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8279 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16097 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24376 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16097 times.
✓ Branch 9 taken 8279 times.
24377 for (auto const &ha_info : ha_list) {
2502 int err;
2503 16097 auto ht = ha_info.ht();
2504
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16096 times.
16097 assert(ht);
2505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16096 times.
16096 if (!ht->savepoint_set) {
2506 my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT");
2507 error = 1;
2508 break;
2509 }
2510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16098 times.
16098 if ((err = ht->savepoint_set(
2511 ht, thd,
2512
1/2
✓ Branch 0 taken 16098 times.
✗ Branch 1 not taken.
16096 (uchar *)(sv + 1) + ht->savepoint_offset))) { // cannot happen
2513 char errbuf[MYSQL_ERRMSG_SIZE];
2514 my_error(ER_GET_ERRNO, MYF(0), err,
2515 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2516 error = 1;
2517 }
2518
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16098 times.
16098 assert(!thd->status_var_aggregated);
2519
1/2
✓ Branch 0 taken 16098 times.
✗ Branch 1 not taken.
16098 thd->status_var.ha_savepoint_count++;
2520 8279 }
2521 /*
2522 Remember the list of registered storage engines. All new
2523 engines are prepended to the beginning of the list.
2524 */
2525
1/2
✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
8279 sv->ha_list = ha_list.head();
2526
2527 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
2528
3/4
✓ Branch 0 taken 8279 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8275 times.
✓ Branch 3 taken 4 times.
8279 if (!error && thd->m_transaction_psi != nullptr)
2529
1/2
✓ Branch 0 taken 8275 times.
✗ Branch 1 not taken.
8275 MYSQL_INC_TRANSACTION_SAVEPOINTS(thd->m_transaction_psi, 1);
2530 #endif
2531
2532 8279 return error;
2533 8279 }
2534
2535 137 int ha_release_savepoint(THD *thd, SAVEPOINT *sv) {
2536 137 int error = 0;
2537
1/2
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
137 DBUG_TRACE;
2538
2539
1/2
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
137 Ha_trx_info_list ha_list{sv->ha_list};
2540
7/12
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 196 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 196 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 333 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 196 times.
✓ Branch 11 taken 137 times.
333 for (auto const &ha_info : ha_list) {
2541 int err;
2542 196 auto ht = ha_info.ht();
2543 /* Savepoint life time is enclosed into transaction life time. */
2544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
196 assert(ht);
2545
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 126 times.
196 if (!ht->savepoint_release) continue;
2546
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if ((err = ht->savepoint_release(
2547 ht, thd,
2548
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 (uchar *)(sv + 1) + ht->savepoint_offset))) { // cannot happen
2549 char errbuf[MYSQL_ERRMSG_SIZE];
2550 my_error(ER_GET_ERRNO, MYF(0), err,
2551 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, err));
2552 error = 1;
2553 }
2554 137 }
2555
4/6
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 136 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
137 DBUG_EXECUTE_IF("fail_ha_release_savepoint", {
2556 my_error(ER_UNKNOWN_ERROR, MYF(0));
2557 error = 1;
2558 });
2559
2560 #ifdef HAVE_PSI_TRANSACTION_INTERFACE
2561
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 1 times.
137 if (thd->m_transaction_psi != nullptr)
2562
1/2
✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
136 MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(thd->m_transaction_psi, 1);
2563 #endif
2564 137 return error;
2565 137 }
2566
2567 231 static bool clone_snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg) {
2568 231 handlerton *const hton = plugin_data<handlerton *>(plugin);
2569
2570
3/4
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 189 times.
231 if (hton->state == SHOW_OPTION_YES && hton->clone_consistent_snapshot)
2571 42 hton->clone_consistent_snapshot(hton, thd, static_cast<THD *>(arg));
2572
2573 231 return false;
2574 }
2575
2576 26 static int ha_clone_consistent_snapshot(THD *thd) {
2577 26 THD_ptr from_thd_ptr;
2578 ulong id;
2579 26 Item *val = thd->lex->donor_transaction_id;
2580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 assert(val);
2581
2582
3/4
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
26 if (thd->lex->table_or_sp_used()) {
2583
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(ER_NOT_SUPPORTED_YET, MYF(0),
2584 "Usage of subqueries or stored "
2585 "function calls as part of this statement");
2586 1 goto error;
2587 }
2588
2589
9/12
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 24 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 24 times.
25 if ((!val->fixed && val->fix_fields(thd, &val)) || val->check_cols(1)) {
2590
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(ER_SET_CONSTANTS_ONLY, MYF(0));
2591 1 goto error;
2592 }
2593
2594
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 id = val->val_int();
2595
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 23 times.
24 if (thd->thread_id() == id) {
2596
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 my_error(ER_NO_SUCH_THREAD, MYF(0), id);
2597 1 goto error;
2598 }
2599
2600 {
2601 23 Find_thd_with_id find_thd_with_id(id, true);
2602
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 from_thd_ptr = Global_THD_manager::get_instance()->find_thd(&find_thd_with_id);
2603
2604
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
23 if (!from_thd_ptr) {
2605
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 my_error(ER_NO_SUCH_THREAD, MYF(0), id);
2606 2 goto error;
2607 }
2608
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
23 }
2609
2610 /*
2611 Blocking commits and binlog updates ensures that we get the same snapshot
2612 for all engines (including the binary log). This allows us among other
2613 things to do backups with START TRANSACTION WITH CONSISTENT SNAPSHOT and
2614 have a consistent binlog position.
2615 */
2616
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 tc_log->xlock();
2617
2618
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 plugin_foreach(thd, clone_snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
2619 from_thd_ptr.get());
2620
2621
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 tc_log->xunlock();
2622
2623 21 return 0;
2624
2625 5 error:
2626
2627 5 return 1;
2628 26 }
2629
2630 704 static bool start_snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg) {
2631 704 handlerton *const hton = plugin_data<handlerton *>(plugin);
2632
4/4
✓ Branch 0 taken 695 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 119 times.
✓ Branch 3 taken 576 times.
704 if (hton->state == SHOW_OPTION_YES && hton->start_consistent_snapshot) {
2633 119 hton->start_consistent_snapshot(hton, thd);
2634 119 *((bool *)arg) = false;
2635 }
2636 704 return false;
2637 }
2638
2639 90 int ha_start_consistent_snapshot(THD *thd) {
2640
3/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
90 if (thd->lex->donor_transaction_id) return ha_clone_consistent_snapshot(thd);
2641 64 bool warn = true;
2642
2643 /*
2644 Blocking commits and binlog updates ensures that we get the same snapshot
2645 for all engines (including the binary log). This allows us among other
2646 things to do backups with START TRANSACTION WITH CONSISTENT SNAPSHOT and
2647 have a consistent binlog position.
2648 */
2649
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 tc_log->xlock();
2650
2651
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 plugin_foreach(thd, start_snapshot_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
2652 &warn);
2653
2654
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 tc_log->xunlock();
2655
2656 /*
2657 Same idea as when one wants to CREATE TABLE in one engine which does not
2658 exist:
2659 */
2660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (warn)
2661 push_warning(thd, Sql_condition::SL_WARNING, ER_UNKNOWN_ERROR,
2662 "This MySQL server does not support any "
2663 "consistent-read capable storage engine");
2664 64 return 0;
2665 }
2666
2667 2739 static bool store_binlog_info_handlerton(THD *thd, plugin_ref plugin,
2668 void *arg) {
2669 2739 handlerton *const hton = plugin_data<handlerton *>(plugin);
2670
2671
3/4
✓ Branch 0 taken 2739 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 249 times.
✓ Branch 3 taken 2490 times.
2739 if (hton->state == SHOW_OPTION_YES && hton->store_binlog_info) {
2672 249 hton->store_binlog_info(hton, thd);
2673 249 *(static_cast<bool *>(arg)) = false;
2674 }
2675
2676 2739 return false;
2677 }
2678
2679 254 int ha_store_binlog_info(THD *thd) {
2680
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 249 times.
254 if (!mysql_bin_log.is_open()) return 0;
2681
2682
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 assert(tc_log == &mysql_bin_log);
2683
2684 249 LOG_INFO li;
2685 249 bool warn = true;
2686
2687 /* Block commits to get consistent binlog coordinates */
2688
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 tc_log->xlock();
2689
2690
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 mysql_bin_log.raw_get_current_log(&li);
2691
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 thd->set_trans_pos(li.log_file_name, li.pos);
2692
2693
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 plugin_foreach(thd, store_binlog_info_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
2694 &warn);
2695
2696
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 tc_log->xunlock();
2697
2698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 249 times.
249 if (warn)
2699 push_warning(thd, Sql_condition::SL_WARNING, ER_UNKNOWN_ERROR,
2700 "No support for storing binlog coordinates in any storage");
2701 249 return 0;
2702 }
2703
2704 28239695 static bool flush_handlerton(THD *, plugin_ref plugin, void *arg) {
2705 28239695 handlerton *hton = plugin_data<handlerton *>(plugin);
2706
5/6
✓ Branch 0 taken 28236623 times.
✓ Branch 1 taken 3068 times.
✓ Branch 2 taken 2567153 times.
✓ Branch 3 taken 25669470 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 28239658 times.
30806811 if (hton->state == SHOW_OPTION_YES && hton->flush_logs &&
2707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2567120 times.
2567153 hton->flush_logs(hton, *(static_cast<bool *>(arg))))
2708 return true;
2709 28239658 return false;
2710 }
2711
2712 2567153 bool ha_flush_logs(bool binlog_group_flush) {
2713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2567120 times.
2567153 if (plugin_foreach(nullptr, flush_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
2714 static_cast<void *>(&binlog_group_flush))) {
2715 return true;
2716 }
2717 2567120 return false;
2718 }
2719
2720 /**
2721 @brief make canonical filename
2722
2723 @param[in] file table handler
2724 @param[in] path original path
2725 @param[out] tmp_path buffer for canonized path
2726
2727 @details Lower case db name and table name path parts for
2728 non file based tables when lower_case_table_names
2729 is 2 (store as is, compare in lower case).
2730 Filesystem path prefix (mysql_data_home or tmpdir)
2731 is left intact.
2732
2733 @note tmp_path may be left intact if no conversion was
2734 performed.
2735
2736 @retval canonized path
2737
2738 @todo This may be done more efficiently when table path
2739 gets built. Convert this function to something like
2740 ASSERT_CANONICAL_FILENAME.
2741 */
2742 499379 const char *get_canonical_filename(handler *file, const char *path,
2743 char *tmp_path) {
2744 uint i;
2745
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 499379 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 499379 times.
✗ Branch 5 not taken.
499379 if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
2746 499379 return path;
2747
2748 for (i = 0; i <= mysql_tmpdir_list.max; i++) {
2749 if (is_prefix(path, mysql_tmpdir_list.list[i])) return path;
2750 }
2751
2752 /* Ensure that table handler get path in lower case */
2753 if (tmp_path != path) my_stpcpy(tmp_path, path);
2754
2755 /*
2756 we only should turn into lowercase database/table part
2757 so start the process after homedirectory
2758 */
2759 my_casedn_str(files_charset_info, tmp_path + mysql_data_home_len);
2760 return tmp_path;
2761 }
2762
2763 class Ha_delete_table_error_handler : public Internal_error_handler {
2764 public:
2765 19 bool handle_condition(THD *, uint, const char *,
2766 Sql_condition::enum_severity_level *level,
2767 const char *) override {
2768 /* Downgrade errors to warnings. */
2769
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 if (*level == Sql_condition::SL_ERROR) *level = Sql_condition::SL_WARNING;
2770 19 return false;
2771 }
2772 };
2773
2774 /**
2775 Delete table from the storage engine.
2776
2777 @param thd Thread context.
2778 @param table_type Handlerton for table's SE.
2779 @param path Path to table (without extension).
2780 @param db Table database.
2781 @param alias Table name.
2782 @param table_def dd::Table object describing the table.
2783 @param generate_warning Indicates whether errors during deletion
2784 should be reported as warnings.
2785
2786 @return 0 - in case of success, non-0 in case of failure, ENOENT
2787 if the file doesn't exists.
2788 */
2789 169750 int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
2790 const char *db, const char *alias,
2791 const dd::Table *table_def, bool generate_warning) {
2792 handler *file;
2793 char tmp_path[FN_REFLEN];
2794 int error;
2795
1/2
✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
169750 TABLE dummy_table;
2796
1/2
✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
169750 TABLE_SHARE dummy_share;
2797
1/2
✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
169750 DBUG_TRACE;
2798
2799 169750 dummy_table.s = &dummy_share;
2800
2801 /* DB_TYPE_UNKNOWN is used in ALTER TABLE when renaming only .frm files */
2802
2/4
✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 169750 times.
339500 if (table_type == nullptr ||
2803 !(file =
2804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 169750 times.
169750 get_new_handler((TABLE_SHARE *)nullptr,
2805
2/4
✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 169750 times.
✗ Branch 3 not taken.
169750 table_def->partition_type() != dd::Table::PT_NONE,
2806 thd->mem_root, table_type))) {
2807 return ENOENT;
2808 }
2809
2810
1/2
✓ Branch 0 taken 169750 times.
✗ Branch 1 not taken.
169750 path = get_canonical_filename(file, path, tmp_path);
2811
2812
7/8
✓ Branch 0 taken 169741 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 169717 times.
✓ Branch 4 taken 19 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 169722 times.
169750 if ((error = file->ha_delete_table(path, table_def)) && generate_warning) {
2813 /*
2814 Because file->print_error() use my_error() to generate the error message
2815 we use an internal error handler to intercept it and store the text
2816 in a temporary buffer. Later the message will be presented to user
2817 as a warning.
2818 */
2819 19 Ha_delete_table_error_handler ha_delete_table_error_handler;
2820
2821 /* Fill up strucutures that print_error may need */
2822 19 dummy_share.path.str = const_cast<char *>(path);
2823 19 dummy_share.path.length = strlen(path);
2824 19 dummy_share.db.str = db;
2825 19 dummy_share.db.length = strlen(db);
2826 19 dummy_share.table_name.str = alias;
2827 19 dummy_share.table_name.length = strlen(alias);
2828 19 dummy_table.alias = alias;
2829
2830
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 file->change_table_ptr(&dummy_table, &dummy_share);
2831
2832 /*
2833 XXX: should we convert *all* errors to warnings here?
2834 What if the error is fatal?
2835 */
2836
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 thd->push_internal_handler(&ha_delete_table_error_handler);
2837
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 file->print_error(error, 0);
2838
2839
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 thd->pop_internal_handler();
2840 19 }
2841
2842
2/2
✓ Branch 0 taken 169717 times.
✓ Branch 1 taken 24 times.
169741 if (error == 0) {
2843
1/2
✓ Branch 0 taken 169716 times.
✗ Branch 1 not taken.
169717 bool failure = compression_dict::cols_table_delete(thd, *table_def);
2844
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 169715 times.
169716 if (failure) {
2845
3/30
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
1 DBUG_LOG("zip_dict",
2846 "Removing entry from compression dictionary cols"
2847 " failed for table: "
2848 << table_def->name()
2849 << " and table_id: " << table_def->id());
2850 1 error = ER_UNKNOWN_ERROR;
2851 }
2852 }
2853
2854 169740 destroy(file);
2855
2856 #ifdef HAVE_PSI_TABLE_INTERFACE
2857
2/2
✓ Branch 0 taken 169716 times.
✓ Branch 1 taken 25 times.
169741 if (likely(error == 0)) {
2858 /* Table share not available, so check path for temp_table prefix. */
2859 169716 bool temp_table = (strstr(path, tmp_file_prefix) != nullptr);
2860 PSI_TABLE_CALL(drop_table_share)
2861
1/2
✓ Branch 0 taken 169716 times.
✗ Branch 1 not taken.
169716 (temp_table, db, strlen(db), alias, strlen(alias));
2862 }
2863 #endif
2864
2865 169741 return error;
2866 169741 }
2867
2868 // Prepare HA_CREATE_INFO to be used by ALTER as well as upgrade code.
2869 109146 void HA_CREATE_INFO::init_create_options_from_share(const TABLE_SHARE *share,
2870 uint64_t used_fields) {
2871
2/2
✓ Branch 0 taken 109134 times.
✓ Branch 1 taken 12 times.
109146 if (!(used_fields & HA_CREATE_USED_MIN_ROWS)) min_rows = share->min_rows;
2872
2873
2/2
✓ Branch 0 taken 109126 times.
✓ Branch 1 taken 20 times.
109146 if (!(used_fields & HA_CREATE_USED_MAX_ROWS)) max_rows = share->max_rows;
2874
2875
2/2
✓ Branch 0 taken 109134 times.
✓ Branch 1 taken 12 times.
109146 if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
2876 109134 avg_row_length = share->avg_row_length;
2877
2878
2/2
✓ Branch 0 taken 106449 times.
✓ Branch 1 taken 2697 times.
109146 if (!(used_fields & HA_CREATE_USED_DEFAULT_CHARSET))
2879 106449 default_table_charset = share->table_charset;
2880
2881
2/2
✓ Branch 0 taken 109062 times.
✓ Branch 1 taken 84 times.
109146 if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
2882 109062 key_block_size = share->key_block_size;
2883
2884
2/2
✓ Branch 0 taken 109143 times.
✓ Branch 1 taken 3 times.
109146 if (!(used_fields & HA_CREATE_USED_STATS_SAMPLE_PAGES))
2885 109143 stats_sample_pages = share->stats_sample_pages;
2886
2887
2/2
✓ Branch 0 taken 109139 times.
✓ Branch 1 taken 7 times.
109146 if (!(used_fields & HA_CREATE_USED_STATS_AUTO_RECALC))
2888 109139 stats_auto_recalc = share->stats_auto_recalc;
2889
2890
2/2
✓ Branch 0 taken 103342 times.
✓ Branch 1 taken 5804 times.
109146 if (!(used_fields & HA_CREATE_USED_TABLESPACE))
2891 103342 tablespace = share->tablespace;
2892
2893
2/2
✓ Branch 0 taken 109142 times.
✓ Branch 1 taken 4 times.
109146 if (storage_media == HA_SM_DEFAULT)
2894 109142 storage_media = share->default_storage_media;
2895
2896 /* Creation of federated table with LIKE clause needs connection string */
2897
1/2
✓ Branch 0 taken 109146 times.
✗ Branch 1 not taken.
109146 if (!(used_fields & HA_CREATE_USED_CONNECTION))
2898 109146 connect_string = share->connect_string;
2899
2900
2/2
✓ Branch 0 taken 108173 times.
✓ Branch 1 taken 973 times.
109146 if (!(used_fields & HA_CREATE_USED_COMMENT)) {
2901 // Assert to check that used_fields flag and comment are in sync.
2902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108173 times.
108173 assert(!comment.str);
2903 108173 comment = share->comment;
2904 }
2905
2906
2/2
✓ Branch 0 taken 109072 times.
✓ Branch 1 taken 74 times.
109146 if (!(used_fields & HA_CREATE_USED_COMPRESS)) {
2907 // Assert to check that used_fields flag and compress are in sync
2908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109072 times.
109072 assert(!compress.str);
2909 109072 compress = share->compress;
2910 }
2911
2912
2/2
✓ Branch 0 taken 104069 times.
✓ Branch 1 taken 5077 times.
109146 if (!(used_fields & (HA_CREATE_USED_ENCRYPT))) {
2913 // Assert to check that used_fields flag and encrypt_type are in sync
2914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 104069 times.
104069 assert(!encrypt_type.str);
2915 104069 encrypt_type = share->encrypt_type;
2916 104069 explicit_encryption = share->explicit_encryption;
2917 } else {
2918 5077 explicit_encryption = true;
2919 }
2920
2921
2/2
✓ Branch 0 taken 109078 times.
✓ Branch 1 taken 68 times.
109146 if (!(used_fields & HA_CREATE_USED_SECONDARY_ENGINE)) {
2922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 109078 times.
109078 assert(secondary_engine.str == nullptr);
2923 109078 secondary_engine = share->secondary_engine;
2924 }
2925
2926
2/2
✓ Branch 0 taken 104111 times.
✓ Branch 1 taken 5035 times.
109146 if (!(used_fields & HA_CREATE_USED_AUTOEXTEND_SIZE)) {
2927 /* m_implicit_tablespace_autoextend_size = 0 is a valid value. Hence,
2928 we need a mechanism to indicate the value change. */
2929 104111 m_implicit_tablespace_autoextend_size = share->autoextend_size;
2930 104111 m_implicit_tablespace_autoextend_size_change = false;
2931 }
2932
2933
2/2
✓ Branch 0 taken 107847 times.
✓ Branch 1 taken 1299 times.
109146 if (!(used_fields & HA_CREATE_USED_ENCRYPTION_KEY_ID)) {
2934 107847 encryption_key_id = share->encryption_key_id;
2935 107847 was_encryption_key_id_set = share->was_encryption_key_id_set;
2936 }
2937
2938
2/2
✓ Branch 0 taken 109140 times.
✓ Branch 1 taken 6 times.
109146 if (engine_attribute.str == nullptr)
2939 109140 engine_attribute = share->engine_attribute;
2940
2941
2/2
✓ Branch 0 taken 109136 times.
✓ Branch 1 taken 10 times.
109146 if (secondary_engine_attribute.str == nullptr)
2942 109136 secondary_engine_attribute = share->secondary_engine_attribute;
2943 109146 }
2944
2945 /****************************************************************************
2946 ** General handler functions
2947 ****************************************************************************/
2948 438583 handler *handler::clone(const char *name, MEM_ROOT *mem_root) {
2949
1/2
✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
438583 DBUG_TRACE;
2950
2951 handler *new_handler =
2952
2/4
✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 438583 times.
✗ Branch 3 not taken.
438583 table ? get_new_handler(table->s, (table->s->m_part_info != nullptr),
2953 mem_root, ht)
2954 438583 : nullptr;
2955
2956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 438583 times.
438583 if (!new_handler) return nullptr;
2957
2/4
✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 438583 times.
438583 if (new_handler->set_ha_share_ref(ha_share)) goto err;
2958
2959 /*
2960 Allocate handler->ref here because otherwise ha_open will allocate it
2961 on this->table->mem_root and we will not be able to reclaim that memory
2962 when the clone handler object is destroyed.
2963 */
2964 438583 if (!(new_handler->ref =
2965
2/4
✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 438583 times.
438583 (uchar *)mem_root->Alloc(ALIGN_SIZE(ref_length) * 2)))
2966 goto err;
2967
2968 438583 new_handler->cloned = true;
2969
2970 /*
2971 TODO: Implement a more efficient way to have more than one index open for
2972 the same table instance. The ha_open call is not cacheable for clone.
2973 */
2974
3/4
✓ Branch 0 taken 438583 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 438581 times.
438583 if (new_handler->ha_open(table, name, table->db_stat,
2975 HA_OPEN_IGNORE_IF_LOCKED,
2976 438583 table->get_tmp_dd_table_ptr()))
2977 2 goto err;
2978
2979 438581 return new_handler;
2980
2981 2 err:
2982 2 destroy(new_handler);
2983 2 return nullptr;
2984 438583 }
2985
2986 1191240168 void handler::ha_statistic_increment(
2987 ulonglong System_status_var::*offset) const {
2988
2/4
✓ Branch 0 taken 1191241045 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1191241657 times.
✗ Branch 3 not taken.
1191240168 if (table && table->in_use) (table->in_use->status_var.*offset)++;
2989 1191240168 }
2990
2991 2000269187 THD *handler::ha_thd() const {
2992
2/2
✓ Branch 0 taken 3684117 times.
✓ Branch 1 taken 1996586540 times.
2000269187 if (unlikely(cloned)) return current_thd;
2993
4/6
✓ Branch 0 taken 1985164853 times.
✓ Branch 1 taken 11421687 times.
✓ Branch 2 taken 1985166941 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1985166897 times.
1996586540 assert(table == nullptr || table->in_use == nullptr ||
2994 table->in_use == current_thd);
2995
3/4
✓ Branch 0 taken 1985167962 times.
✓ Branch 1 taken 11418534 times.
✓ Branch 2 taken 1985168550 times.
✗ Branch 3 not taken.
1996586496 return table != nullptr && table->in_use != nullptr ? table->in_use
2996 1996586496 : current_thd;
2997 }
2998
2999 106649895 void handler::unbind_psi() {
3000 #ifdef HAVE_PSI_TABLE_INTERFACE
3001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106649895 times.
106649895 assert(m_lock_type == F_UNLCK);
3002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106649895 times.
106649895 assert(inited == NONE);
3003 /*
3004 Notify the instrumentation that this table is not owned
3005 by this thread any more.
3006 */
3007 106649895 PSI_TABLE_CALL(unbind_table)(m_psi);
3008 #endif
3009 106649886 }
3010
3011 102491196 void handler::rebind_psi() {
3012 #ifdef HAVE_PSI_TABLE_INTERFACE
3013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102491196 times.
102491196 assert(m_lock_type == F_UNLCK);
3014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102491196 times.
102491196 assert(inited == NONE);
3015 /*
3016 Notify the instrumentation that this table is now owned
3017 by this thread.
3018 */
3019 102491196 PSI_table_share *share_psi = ha_table_share_psi(table_share);
3020 102491814 m_psi = PSI_TABLE_CALL(rebind_table)(share_psi, this, m_psi);
3021 #endif
3022 102491940 }
3023
3024 15499064 void handler::start_psi_batch_mode() {
3025 #ifdef HAVE_PSI_TABLE_INTERFACE
3026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15499064 times.
15499064 assert(m_psi_batch_mode == PSI_BATCH_MODE_NONE);
3027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15499064 times.
15499064 assert(m_psi_locker == nullptr);
3028 15499064 m_psi_batch_mode = PSI_BATCH_MODE_STARTING;
3029 15499064 m_psi_numrows = 0;
3030 #endif
3031 15499064 }
3032
3033 15499023 void handler::end_psi_batch_mode() {
3034 #ifdef HAVE_PSI_TABLE_INTERFACE
3035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15499023 times.
15499023 assert(m_psi_batch_mode != PSI_BATCH_MODE_NONE);
3036
2/2
✓ Branch 0 taken 1240523 times.
✓ Branch 1 taken 14258500 times.
15499023 if (m_psi_locker != nullptr) {
3037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1240523 times.
1240523 assert(m_psi_batch_mode == PSI_BATCH_MODE_STARTED);
3038 1240523 PSI_TABLE_CALL(end_table_io_wait)(m_psi_locker, m_psi_numrows);
3039 1240523 m_psi_locker = nullptr;
3040 }
3041 15499023 m_psi_batch_mode = PSI_BATCH_MODE_NONE;
3042 #endif
3043 15499023 }
3044
3045 107717800 PSI_table_share *handler::ha_table_share_psi(const TABLE_SHARE *share) const {
3046 107717800 return share->m_psi;
3047 }
3048
3049 /*
3050 Open database handler object.
3051
3052 Used for opening tables. The name will be the name of the file.
3053 A table is opened when it needs to be opened. For instance
3054 when a request comes in for a select on the table (tables are not
3055 open and closed for each request, they are cached).
3056
3057 The server opens all tables by calling ha_open() which then calls
3058 the handler specific open().
3059
3060 Try O_RDONLY if cannot open as O_RDWR. Don't wait for locks if not
3061 HA_OPEN_WAIT_IF_LOCKED is set
3062
3063 @param [out] table_arg Table structure.
3064 @param name Full path of table name.
3065 @param mode Open mode flags.
3066 @param test_if_locked ?
3067 @param table_def dd::Table object describing table
3068 being open. Can be NULL for temporary
3069 tables created by optimizer.
3070
3071 @retval >0 Error.
3072 @retval 0 Success.
3073 */
3074
3075 5226484 int handler::ha_open(TABLE *table_arg, const char *name, int mode,
3076 int test_if_locked, const dd::Table *table_def) {
3077 int error;
3078
1/2
✓ Branch 0 taken 5226500 times.
✗ Branch 1 not taken.
5226484 DBUG_TRACE;
3079
5/8
✓ Branch 0 taken 5226492 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5226499 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 58 times.
✓ Branch 5 taken 5226441 times.
✓ Branch 6 taken 57 times.
✗ Branch 7 not taken.
5226500 DBUG_PRINT("enter",
3080 ("name: %s db_type: %d db_stat: %d mode: %d lock_test: %d",
3081 name, ht->db_type, table_arg->db_stat, mode, test_if_locked));
3082
3083 5226498 table = table_arg;
3084
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5226498 times.
5226498 assert(table->s == table_share);
3085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5226498 times.
5226498 assert(m_lock_type == F_UNLCK);
3086
5/8
✓ Branch 0 taken 5226495 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5226498 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 56 times.
✓ Branch 5 taken 5226442 times.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
5226498 DBUG_PRINT("info", ("old m_lock_type: %d F_UNLCK %d", m_lock_type, F_UNLCK));
3087 10452994 MEM_ROOT *mem_root = (test_if_locked & HA_OPEN_TMP_TABLE)
3088
2/2
✓ Branch 0 taken 600236 times.
✓ Branch 1 taken 4626261 times.
5226497 ? &table->s->mem_root
3089 4626261 : &table->mem_root;
3090
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5226489 times.
5226497 assert(alloc_root_inited(mem_root));
3091
3092
2/2
✓ Branch 0 taken 438583 times.
✓ Branch 1 taken 4787906 times.
5226489 if (cloned) {
3093
4/6
✓ Branch 0 taken 438581 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 438581 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 438581 times.
✗ Branch 5 not taken.
438583 DEBUG_SYNC(ha_thd(), "start_handler_ha_open_cloned");
3094 }
3095
3096
3/4
✓ Branch 0 taken 5226497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 5226230 times.
5226489 if ((error = open(name, mode, test_if_locked, table_def))) {
3097
2/6
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 267 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
267 if ((error == EACCES || error == EROFS) && mode == O_RDWR &&
3098 (table->db_stat & HA_TRY_READ_ONLY)) {
3099 table->db_stat |= HA_READ_ONLY;
3100 error = open(name, O_RDONLY, test_if_locked, table_def);
3101 }
3102 }
3103
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 5226230 times.
5226497 if (error) {
3104
1/2
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
267 set_my_errno(error); /* Safeguard */
3105
3/8
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 267 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
267 DBUG_PRINT("error", ("error: %d errno: %d", error, errno));
3106 } else {
3107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5226230 times.
5226230 assert(m_psi == nullptr);
3108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5226230 times.
5226230 assert(table_share != nullptr);
3109 #ifdef HAVE_PSI_TABLE_INTERFACE
3110
1/2
✓ Branch 0 taken 5226232 times.
✗ Branch 1 not taken.
5226230 PSI_table_share *share_psi = ha_table_share_psi(table_share);
3111
1/2
✓ Branch 0 taken 5226233 times.
✗ Branch 1 not taken.
5226232 m_psi = PSI_TABLE_CALL(open_table)(share_psi, this);
3112 #endif
3113
3114
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 5226214 times.
5226233 if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA)
3115 19 table->db_stat |= HA_READ_ONLY;
3116
1/2
✓ Branch 0 taken 5226228 times.
✗ Branch 1 not taken.
5226233 (void)extra(HA_EXTRA_NO_READCHECK); // Not needed in SQL
3117
3118 /* ref is already allocated for us if we're called from handler::clone() */
3119
5/8
✓ Branch 0 taken 4787648 times.
✓ Branch 1 taken 438580 times.
✓ Branch 2 taken 4787650 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4787650 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5226230 times.
5226228 if (!ref && !(ref = (uchar *)mem_root->Alloc(ALIGN_SIZE(ref_length) * 2))) {
3120 ha_close();
3121 error = HA_ERR_OUT_OF_MEM;
3122 } else
3123 5226230 dup_ref = ref + ALIGN_SIZE(ref_length);
3124
3125 // Give the table a defined starting cursor, even if it never actually seeks
3126 // or writes. This is important for things like weedout on const tables
3127 // (which is a nonsensical combination, but can happen).
3128 5226230 memset(ref, 0, ref_length);
3129
1/2
✓ Branch 0 taken 5226228 times.
✗ Branch 1 not taken.
5226230 cached_table_flags = table_flags();
3130 }
3131
3132
2/2
✓ Branch 0 taken 1465 times.
✓ Branch 1 taken 5225032 times.
5226495 if (unlikely(opt_userstat)) {
3133 1465 rows_read = rows_changed = 0;
3134 1465 memset(index_rows_read, 0, sizeof(index_rows_read));
3135 }
3136
3137 5226500 return error;
3138 5226497 }
3139
3140 /**
3141 Close handler.
3142
3143 Called from sql_base.cc, sql_select.cc, and table.cc.
3144 In sql_select.cc it is only used to close up temporary tables or during
3145 the process where a temporary table is converted over to being a
3146 myisam table.
3147 For sql_base.cc look at close_data_tables().
3148
3149 @return Operation status
3150 @retval 0 Success
3151 @retval != 0 Error (error code returned)
3152 */
3153
3154 4511446 int handler::ha_close(void) {
3155
1/2
✓ Branch 0 taken 4511451 times.
✗ Branch 1 not taken.
4511446 DBUG_TRACE;
3156 #ifdef HAVE_PSI_TABLE_INTERFACE
3157
1/2
✓ Branch 0 taken 4511451 times.
✗ Branch 1 not taken.
4511451 PSI_TABLE_CALL(close_table)(table_share, m_psi);
3158 4511451 m_psi = nullptr; /* instrumentation handle, invalid after close_table() */
3159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
4511451 assert(m_psi_batch_mode == PSI_BATCH_MODE_NONE);
3160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
4511451 assert(m_psi_locker == nullptr);
3161 #endif
3162 // TODO: set table= NULL to mark the handler as closed?
3163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
4511451 assert(m_psi == nullptr);
3164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
4511451 assert(m_lock_type == F_UNLCK);
3165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4511451 times.
4511451 assert(inited == NONE);
3166
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 4511399 times.
4511451 if (m_unique) {
3167 // It's allocated on memroot and will be freed along with it
3168
1/2
✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
52 m_unique->cleanup();
3169 52 m_unique = nullptr;
3170 }
3171
1/2
✓ Branch 0 taken 4511451 times.
✗ Branch 1 not taken.
9022902 return close();
3172 4511451 }
3173
3174 /**
3175 Initialize use of index.
3176
3177 @param idx Index to use
3178 @param sorted Use sorted order
3179
3180 @return Operation status
3181 @retval 0 Success
3182 @retval != 0 Error (error code returned)
3183 */
3184
3185 72291445 int handler::ha_index_init(uint idx, bool sorted) {
3186
2/4
✓ Branch 0 taken 72291658 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 72291658 times.
72291445 DBUG_EXECUTE_IF("ha_index_init_fail", return HA_ERR_TABLE_DEF_CHANGED;);
3187 int result;
3188
1/2
✓ Branch 0 taken 72291757 times.
✗ Branch 1 not taken.
72291658 DBUG_TRACE;
3189
3/4
✓ Branch 0 taken 72241300 times.
✓ Branch 1 taken 50457 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 72241300 times.
72291757 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72291757 times.
72291757 assert(inited == NONE);
3191
3/4
✓ Branch 0 taken 72291687 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72291666 times.
✓ Branch 3 taken 21 times.
72291757 if (!(result = index_init(idx, sorted))) inited = INDEX;
3192 72291687 mrr_have_range = false;
3193 72291687 end_range = nullptr;
3194 72291687 return result;
3195 72291687 }
3196
3197 /**
3198 End use of index.
3199
3200 @return Operation status
3201 @retval 0 Success
3202 @retval != 0 Error (error code returned)
3203 */
3204
3205 72291720 int handler::ha_index_end() {
3206
1/2
✓ Branch 0 taken 72291738 times.
✗ Branch 1 not taken.
72291720 DBUG_TRACE;
3207 /* SQL HANDLER function can call this without having it locked. */
3208
5/6
✓ Branch 0 taken 72291565 times.
✓ Branch 1 taken 173 times.
✓ Branch 2 taken 72241125 times.
✓ Branch 3 taken 50440 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 72241125 times.
72291738 assert(table->open_by_handler || table_share->tmp_table != NO_TMP_TABLE ||
3209 m_lock_type != F_UNLCK);
3210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72291738 times.
72291738 assert(inited == INDEX);
3211 72291738 inited = NONE;
3212 72291738 end_range = nullptr;
3213 72291738 m_record_buffer = nullptr;
3214
3/4
✓ Branch 0 taken 495 times.
✓ Branch 1 taken 72291243 times.
✓ Branch 2 taken 495 times.
✗ Branch 3 not taken.
72291738 if (m_unique) m_unique->reset(false);
3215
1/2
✓ Branch 0 taken 72291736 times.
✗ Branch 1 not taken.
144583478 return index_end();
3216 72291736 }
3217
3218 /**
3219 Initialize table for random read or scan.
3220
3221 @param scan if true: Initialize for random scans through rnd_next()
3222 if false: Initialize for random reads through rnd_pos()
3223
3224 @return Operation status
3225 @retval 0 Success
3226 @retval != 0 Error (error code returned)
3227 */
3228
3229 15952051 int handler::ha_rnd_init(bool scan) {
3230
2/4
✓ Branch 0 taken 15952052 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15952052 times.
15952051 DBUG_EXECUTE_IF("ha_rnd_init_fail", return HA_ERR_TABLE_DEF_CHANGED;);
3231 int result;
3232
1/2
✓ Branch 0 taken 15952053 times.
✗ Branch 1 not taken.
15952052 DBUG_TRACE;
3233
3/4
✓ Branch 0 taken 12989811 times.
✓ Branch 1 taken 2962242 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12989811 times.
15952053 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3234
4/6
✓ Branch 0 taken 2297165 times.
✓ Branch 1 taken 13654888 times.
✓ Branch 2 taken 2297165 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2297165 times.
✗ Branch 5 not taken.
15952053 assert(inited == NONE || (inited == RND && scan));
3235
6/6
✓ Branch 0 taken 5135564 times.
✓ Branch 1 taken 10816489 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5135561 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 15952050 times.
15952053 if (scan && is_using_prohibited_gap_locks(table, false)) {
3236 2 return HA_ERR_LOCK_DEADLOCK;
3237 }
3238
3/4
✓ Branch 0 taken 15952046 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 15952045 times.
15952050 inited = (result = rnd_init(scan)) ? NONE : RND;
3239 15952046 end_range = nullptr;
3240 15952046 return result;
3241 15952048 }
3242
3243 /**
3244 End use of random access.
3245
3246 @return Operation status
3247 @retval 0 Success
3248 @retval != 0 Error (error code returned)
3249 */
3250
3251 13654808 int handler::ha_rnd_end() {
3252
1/2
✓ Branch 0 taken 13654809 times.
✗ Branch 1 not taken.
13654808 DBUG_TRACE;
3253 /* SQL HANDLER function can call this without having it locked. */
3254
5/6
✓ Branch 0 taken 13654641 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 12940024 times.
✓ Branch 3 taken 714617 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12940024 times.
13654809 assert(table->open_by_handler || table_share->tmp_table != NO_TMP_TABLE ||
3255 m_lock_type != F_UNLCK);
3256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13654809 times.
13654809 assert(inited == RND);
3257 13654809 inited = NONE;
3258 13654809 end_range = nullptr;
3259 13654809 m_record_buffer = nullptr;
3260
1/2
✓ Branch 0 taken 13654807 times.
✗ Branch 1 not taken.
27309616 return rnd_end();
3261 13654807 }
3262
3263 /**
3264 Read next row via random scan.
3265
3266 @param buf Buffer to read the row into
3267
3268 @return Operation status
3269 @retval 0 Success
3270 @retval != 0 Error (error code returned)
3271 */
3272
3273 531538418 int handler::ha_rnd_next(uchar *buf) {
3274 int result;
3275
3/4
✓ Branch 0 taken 531538790 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 531538789 times.
531538418 DBUG_EXECUTE_IF("ha_rnd_next_deadlock", return HA_ERR_LOCK_DEADLOCK;);
3276
1/2
✓ Branch 0 taken 531539527 times.
✗ Branch 1 not taken.
531538789 DBUG_TRACE;
3277
3/4
✓ Branch 0 taken 415653600 times.
✓ Branch 1 taken 115885927 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 415653600 times.
531539527 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 531539527 times.
531539527 assert(inited == RND);
3279
3280 // Set status for the need to update generated fields
3281 531539527 m_update_generated_read_fields = table->has_gcol();
3282
3283
19/27
✓ Branch 0 taken 80304199 times.
✓ Branch 1 taken 451235397 times.
✓ Branch 2 taken 12166611 times.
✓ Branch 3 taken 274664 times.
✓ Branch 4 taken 67862924 times.
✓ Branch 5 taken 12166611 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 12166599 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12165534 times.
✓ Branch 10 taken 1065 times.
✓ Branch 11 taken 12165533 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 274664 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 274664 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 259016 times.
✓ Branch 18 taken 15648 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 67862924 times.
✓ Branch 21 taken 67861867 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 67618755 times.
✓ Branch 24 taken 243112 times.
✓ Branch 25 taken 451235541 times.
✗ Branch 26 not taken.
531539596 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, MAX_KEY, result,
3284 { result = rnd_next(buf); })
3285
4/4
✓ Branch 0 taken 524964238 times.
✓ Branch 1 taken 6574432 times.
✓ Branch 2 taken 1025662 times.
✓ Branch 3 taken 523938576 times.
531538670 if (!result && m_update_generated_read_fields) {
3286
1/2
✓ Branch 0 taken 1025662 times.
✗ Branch 1 not taken.
1025662 result = update_generated_read_fields(buf, table);
3287 1025662 m_update_generated_read_fields = false;
3288 }
3289 531538670 table->set_row_status_from_handler(result);
3290
3291
2/2
✓ Branch 0 taken 524964204 times.
✓ Branch 1 taken 6575323 times.
531539505 if (likely(!result)) {
3292 524964204 update_index_stats(active_index);
3293 }
3294
3295 531539459 return result;
3296 531539459 }
3297
3298 /**
3299 Read row via random scan from position.
3300
3301 @param[out] buf Buffer to read the row into
3302 @param pos Position from position() call
3303
3304 @return Operation status
3305 @retval 0 Success
3306 @retval != 0 Error (error code returned)
3307 */
3308
3309 23935096 int handler::ha_rnd_pos(uchar *buf, uchar *pos) {
3310 int result;
3311
1/2
✓ Branch 0 taken 23935101 times.
✗ Branch 1 not taken.
23935096 DBUG_TRACE;
3312
3/4
✓ Branch 0 taken 1490188 times.
✓ Branch 1 taken 22444913 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1490188 times.
23935101 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3313 /* TODO: Find out how to solve ha_rnd_pos when finding duplicate update. */
3314 /* assert(inited == RND); */
3315
3316 // Set status for the need to update generated fields
3317 23935101 m_update_generated_read_fields = table->has_gcol();
3318
3319
16/27
✓ Branch 0 taken 1459567 times.
✓ Branch 1 taken 22475534 times.
✓ Branch 2 taken 950554 times.
✓ Branch 3 taken 99707 times.
✓ Branch 4 taken 409306 times.
✓ Branch 5 taken 950554 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 950554 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 950554 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 950554 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 99707 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 99707 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 99707 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 409306 times.
✓ Branch 21 taken 409306 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 409306 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 22475534 times.
✗ Branch 26 not taken.
23935101 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, MAX_KEY, result,
3320 { result = rnd_pos(buf, pos); })
3321
4/4
✓ Branch 0 taken 23935008 times.
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 9278 times.
✓ Branch 3 taken 23925730 times.
23935101 if (!result && m_update_generated_read_fields) {
3322
1/2
✓ Branch 0 taken 9278 times.
✗ Branch 1 not taken.
9278 result = update_generated_read_fields(buf, table);
3323 9278 m_update_generated_read_fields = false;
3324 }
3325 23935101 table->set_row_status_from_handler(result);
3326 23935101 return result;
3327 23935101 }
3328
3329 FT_INFO *handler::ft_init_ext(uint flags [[maybe_unused]],
3330 uint inx [[maybe_unused]],
3331 String *key [[maybe_unused]]) {
3332 my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0));
3333 return nullptr;
3334 }
3335
3336 52366 int handler::ha_ft_read(uchar *buf) {
3337 int result;
3338
1/2
✓ Branch 0 taken 52366 times.
✗ Branch 1 not taken.
52366 DBUG_TRACE;
3339
3340 // Set status for the need to update generated fields
3341 52366 m_update_generated_read_fields = table->has_gcol();
3342
3343
1/2
✓ Branch 0 taken 52366 times.
✗ Branch 1 not taken.
52366 result = ft_read(buf);
3344
4/4
✓ Branch 0 taken 50280 times.
✓ Branch 1 taken 2086 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 50258 times.
52366 if (!result && m_update_generated_read_fields) {
3345
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 result = update_generated_read_fields(buf, table);
3346 22 m_update_generated_read_fields = false;
3347 }
3348 52366 table->set_row_status_from_handler(result);
3349 52366 return result;
3350 52366 }
3351
3352 205 int handler::ha_sample_init(void *&scan_ctx, double sampling_percentage,
3353 int sampling_seed,
3354 enum_sampling_method sampling_method,
3355 const bool tablesample) {
3356
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 DBUG_TRACE;
3357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 assert(sampling_percentage >= 0.0);
3358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 assert(sampling_percentage <= 100.0);
3359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 assert(inited == NONE);
3360
3361 // Initialise the random number generator.
3362
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 m_random_number_engine.seed(sampling_seed);
3363 205 m_sampling_percentage = sampling_percentage;
3364
3365
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 int result = sample_init(scan_ctx, sampling_percentage, sampling_seed,
3366 sampling_method, tablesample);
3367
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
205 inited = (result != 0) ? NONE : SAMPLING;
3368 205 return result;
3369 205 }
3370
3371 204 int handler::ha_sample_end(void *scan_ctx) {
3372
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 DBUG_TRACE;
3373
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 assert(inited == SAMPLING);
3374 204 inited = NONE;
3375
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 int result = sample_end(scan_ctx);
3376 204 return result;
3377 204 }
3378
3379 41125 int handler::ha_sample_next(void *scan_ctx, uchar *buf) {
3380
1/2
✓ Branch 0 taken 41125 times.
✗ Branch 1 not taken.
41125 DBUG_TRACE;
3381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41125 times.
41125 assert(inited == SAMPLING);
3382
3383
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 41025 times.
41125 if (m_sampling_percentage == 0.0) return HA_ERR_END_OF_FILE;
3384
3385 41025 m_update_generated_read_fields = table->has_gcol();
3386
3387 int result;
3388
8/27
✓ Branch 0 taken 40925 times.
✓ Branch 1 taken 100 times.
✓ Branch 2 taken 40925 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 40925 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 40925 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 40925 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 40925 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 100 times.
✗ Branch 26 not taken.
41025 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, MAX_KEY, result,
3389 { result = sample_next(scan_ctx, buf); })
3390
3391
4/4
✓ Branch 0 taken 40824 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 647 times.
✓ Branch 3 taken 40177 times.
41025 if (result == 0 && m_update_generated_read_fields) {
3392
1/2
✓ Branch 0 taken 647 times.
✗ Branch 1 not taken.
647 result = update_generated_read_fields(buf, table);
3393 647 m_update_generated_read_fields = false;
3394 }
3395 41025 table->set_row_status_from_handler(result);
3396
3397
2/2
✓ Branch 0 taken 40824 times.
✓ Branch 1 taken 201 times.
41025 if (likely(!result)) {
3398 40824 update_index_stats(active_index);
3399 }
3400
3401 41025 return result;
3402 41125 }
3403
3404 2 int handler::sample_init(void *&scan_ctx [[maybe_unused]], double, int,
3405 enum_sampling_method, const bool) {
3406 2 return rnd_init(true);
3407 }
3408
3409 2 int handler::sample_end(void *scan_ctx [[maybe_unused]]) { return rnd_end(); }
3410
3411 100 int handler::sample_next(void *scan_ctx [[maybe_unused]], uchar *buf) {
3412 // Temporary set inited to RND, since we are calling rnd_next().
3413
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 int res = rnd_next(buf);
3414
3415
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 std::uniform_real_distribution<double> rnd(0.0, 1.0);
3416
4/8
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 100 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 100 times.
100 while (!res && rnd(m_random_number_engine) > (m_sampling_percentage / 100.0))
3417 res = rnd_next(buf);
3418
3419 100 return res;
3420 }
3421
3422 1153 int handler::records(ha_rows *num_rows) {
3423
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1152 times.
1153 if (ha_table_flags() & HA_COUNT_ROWS_INSTANT) {
3424 1 *num_rows = stats.records;
3425 1 return 0;
3426 }
3427
3428 1152 int error = 0;
3429 1152 ha_rows rows = 0;
3430 1152 start_psi_batch_mode();
3431
3432
1/2
✓ Branch 0 taken 1152 times.
✗ Branch 1 not taken.
1152 if (!(error = ha_rnd_init(true))) {
3433
2/2
✓ Branch 0 taken 940648 times.
✓ Branch 1 taken 1 times.
940649 while (!table->in_use->killed) {
3434
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 940647 times.
940648 DBUG_EXECUTE_IF("bug28079850", table->in_use->killed = THD::KILL_QUERY;);
3435
2/2
✓ Branch 0 taken 1314 times.
✓ Branch 1 taken 939334 times.
940648 if ((error = ha_rnd_next(table->record[0]))) {
3436
2/2
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 1151 times.
1314 if (error == HA_ERR_RECORD_DELETED)
3437 163 continue;
3438 else
3439 1151 break;
3440 }
3441 939334 ++rows;
3442 }
3443 }
3444
3445 1152 *num_rows = rows;
3446 1152 end_psi_batch_mode();
3447 1152 int ha_rnd_end_error = 0;
3448
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1149 times.
1152 if (error != HA_ERR_END_OF_FILE) *num_rows = HA_POS_ERROR;
3449
3450 // Call ha_rnd_end() only if only if handler has been initialized.
3451
3/6
✓ Branch 0 taken 1152 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1152 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1152 times.
1152 if (inited && (ha_rnd_end_error = ha_rnd_end())) *num_rows = HA_POS_ERROR;
3452
3453
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1149 times.
1152 return (error != HA_ERR_END_OF_FILE) ? error : ha_rnd_end_error;
3454 }
3455
3456 21 int handler::records_from_index(ha_rows *num_rows, uint index) {
3457
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 18 times.
21 if (ha_table_flags() & HA_COUNT_ROWS_INSTANT) {
3458 3 *num_rows = stats.records;
3459 3 return 0;
3460 }
3461
3462 18 int error = 0;
3463 18 ha_rows rows = 0;
3464 18 uchar *buf = table->record[0];
3465 18 start_psi_batch_mode();
3466
3467
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (!(error = ha_index_init(index, false))) {
3468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!(error = ha_index_first(buf))) {
3469 rows = 1;
3470
3471 while (!table->in_use->killed) {
3472 DBUG_EXECUTE_IF("bug28079850",
3473 table->in_use->killed = THD::KILL_QUERY;);
3474 if ((error = ha_index_next(buf))) {
3475 if (error == HA_ERR_RECORD_DELETED)
3476 continue;
3477 else
3478 break;
3479 }
3480 ++rows;
3481 }
3482 }
3483 }
3484
3485 18 *num_rows = rows;
3486 18 end_psi_batch_mode();
3487 18 int ha_index_end_error = 0;
3488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (error != HA_ERR_END_OF_FILE) *num_rows = HA_POS_ERROR;
3489
3490 // Call ha_index_end() only if handler has been initialized.
3491
3/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
18 if (inited && (ha_index_end_error = ha_index_end())) *num_rows = HA_POS_ERROR;
3492
3493
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 return (error != HA_ERR_END_OF_FILE) ? error : ha_index_end_error;
3494 }
3495
3496 34125 int handler::handle_records_error(int error, ha_rows *num_rows) {
3497 // If query was killed set the error since not all storage engines do it.
3498
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 34123 times.
34125 if (table->in_use->killed) {
3499 2 *num_rows = HA_POS_ERROR;
3500
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (error == 0) error = HA_ERR_QUERY_INTERRUPTED;
3501 }
3502
3503
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 34052 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
34125 if (error != 0) assert(*num_rows == HA_POS_ERROR);
3504
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 34052 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 73 times.
34125 if (*num_rows == HA_POS_ERROR) assert(error != 0);
3505
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 34052 times.
34125 if (error != 0) {
3506 /*
3507 ha_innobase::records may have rolled back internally.
3508 In this case, thd_mark_transaction_to_rollback() will have been called.
3509 For the errors below, we need to abort right away.
3510 */
3511
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 40 times.
73 switch (error) {
3512 33 case HA_ERR_LOCK_DEADLOCK:
3513 case HA_ERR_LOCK_TABLE_FULL:
3514 case HA_ERR_LOCK_WAIT_TIMEOUT:
3515 case HA_ERR_QUERY_INTERRUPTED:
3516 33 print_error(error, MYF(0));
3517 33 return error;
3518 40 default:
3519 40 return error;
3520 }
3521 }
3522 34052 return 0;
3523 }
3524
3525 /**
3526 Read [part of] row via [part of] index.
3527 @param[out] buf buffer where store the data
3528 @param key Key to search for
3529 @param keypart_map Which part of key to use
3530 @param find_flag Direction/condition on key usage
3531
3532 @returns Operation status
3533 @retval 0 Success (found a record, and function has
3534 set table status to "has row")
3535 @retval HA_ERR_END_OF_FILE Row not found (function has set table status
3536 to "no row"). End of index passed.
3537 @retval HA_ERR_KEY_NOT_FOUND Row not found (function has set table status
3538 to "no row"). Index cursor positioned.
3539 @retval != 0 Error
3540
3541 @note Positions an index cursor to the index specified in the handle.
3542 Fetches the row if available. If the key value is null,
3543 begin at the first key of the index.
3544 ha_index_read_map can be restarted without calling index_end on the previous
3545 index scan and without calling ha_index_init. In this case the
3546 ha_index_read_map is on the same index as the previous ha_index_scan.
3547 This is particularly used in conjunction with multi read ranges.
3548 */
3549
3550 31772640 int handler::ha_index_read_map(uchar *buf, const uchar *key,
3551 key_part_map keypart_map,
3552 enum ha_rkey_function find_flag) {
3553 int result;
3554
1/2
✓ Branch 0 taken 31772865 times.
✗ Branch 1 not taken.
31772640 DBUG_TRACE;
3555
3/4
✓ Branch 0 taken 24449712 times.
✓ Branch 1 taken 7323153 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24449712 times.
31772865 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31772865 times.
31772865 assert(inited == INDEX);
3557
3/4
✓ Branch 0 taken 377296 times.
✓ Branch 1 taken 31395569 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 377296 times.
31772865 assert(!pushed_idx_cond || buf == table->record[0]);
3558
3559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 31772711 times.
31772759 if (is_using_prohibited_gap_locks(
3560 table,
3561 31772865 is_using_full_unique_key(active_index, keypart_map, find_flag))) {
3562 return HA_ERR_LOCK_DEADLOCK;
3563 }
3564
3565 // Set status for the need to update generated fields
3566 31772711 m_update_generated_read_fields = table->has_gcol();
3567
3568
19/27
✓ Branch 0 taken 12465462 times.
✓ Branch 1 taken 19307300 times.
✓ Branch 2 taken 11058423 times.
✓ Branch 3 taken 1372011 times.
✓ Branch 4 taken 35028 times.
✓ Branch 5 taken 11058353 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 11058473 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 11057441 times.
✓ Branch 10 taken 1032 times.
✓ Branch 11 taken 11057441 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1372011 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1372011 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1372009 times.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 35028 times.
✓ Branch 21 taken 35028 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 35025 times.
✓ Branch 24 taken 3 times.
✓ Branch 25 taken 19307316 times.
✗ Branch 26 not taken.
31772762 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result, {
3569 result = index_read_map(buf, key, keypart_map, find_flag);
3570 })
3571
4/4
✓ Branch 0 taken 19419216 times.
✓ Branch 1 taken 12353612 times.
✓ Branch 2 taken 12688 times.
✓ Branch 3 taken 19406528 times.
31772828 if (!result && m_update_generated_read_fields) {
3572
1/2
✓ Branch 0 taken 12688 times.
✗ Branch 1 not taken.
12688 result = update_generated_read_fields(buf, table, active_index);
3573 12688 m_update_generated_read_fields = false;
3574 }
3575 // Filter duplicate records from multi-value index read.
3576 // (m_unique != nullptr in case of multi-value index read)
3577 // In case of range scan, duplicate records are filtered in
3578 // multi_range_read_next()
3579
9/12
✓ Branch 0 taken 19419218 times.
✓ Branch 1 taken 12353610 times.
✓ Branch 2 taken 19102288 times.
✓ Branch 3 taken 316930 times.
✓ Branch 4 taken 256 times.
✓ Branch 5 taken 19102032 times.
✓ Branch 6 taken 256 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 256 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 31772828 times.
31772828 if (!result && !mrr_have_range && m_unique != nullptr && filter_dup_records())
3580 result = HA_ERR_KEY_NOT_FOUND;
3581
3582 31772828 table->set_row_status_from_handler(result);
3583
3584
2/2
✓ Branch 0 taken 19419218 times.
✓ Branch 1 taken 12353675 times.
31772889 if (likely(!result)) {
3585 19419218 update_index_stats(active_index);
3586 }
3587
3588 31772892 return result;
3589 31772892 }
3590
3591 487 int handler::ha_index_read_last_map(uchar *buf, const uchar *key,
3592 key_part_map keypart_map) {
3593 int result;
3594
1/2
✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
487 DBUG_TRACE;
3595
2/4
✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 487 times.
487 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3596
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 487 times.
487 assert(inited == INDEX);
3597
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
487 assert(!pushed_idx_cond || buf == table->record[0]);
3598
3599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 487 times.
487 if (is_using_prohibited_gap_locks(table, false)) {
3600 return HA_ERR_LOCK_DEADLOCK;
3601 }
3602
3603 // Set status for the need to update generated fields
3604 487 m_update_generated_read_fields = table->has_gcol();
3605
3606
5/27
✓ Branch 0 taken 487 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 487 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 487 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 487 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 487 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
487 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result,
3607 { result = index_read_last_map(buf, key, keypart_map); })
3608
4/4
✓ Branch 0 taken 457 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 456 times.
487 if (!result && m_update_generated_read_fields) {
3609
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 result = update_generated_read_fields(buf, table, active_index);
3610 1 m_update_generated_read_fields = false;
3611 }
3612 487 table->set_row_status_from_handler(result);
3613
3614
2/2
✓ Branch 0 taken 457 times.
✓ Branch 1 taken 30 times.
487 if (likely(!result)) {
3615 457 update_index_stats(active_index);
3616 }
3617
3618 487 return result;
3619 487 }
3620
3621 /**
3622 Initializes an index and read it.
3623
3624 @see handler::ha_index_read_map.
3625 */
3626
3627 50798784 int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key,
3628 key_part_map keypart_map,
3629 enum ha_rkey_function find_flag) {
3630 int result;
3631
1/2
✓ Branch 0 taken 50799268 times.
✗ Branch 1 not taken.
50798784 DBUG_TRACE;
3632
3/4
✓ Branch 0 taken 50799160 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50799160 times.
50799268 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50799268 times.
50799268 assert(end_range == nullptr);
3634
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 50799268 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
50799268 assert(!pushed_idx_cond || buf == table->record[0]);
3635
3636
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50798905 times.
50799065 if (is_using_prohibited_gap_locks(
3637 50799268 table, is_using_full_unique_key(index, keypart_map, find_flag))) {
3638 return HA_ERR_LOCK_DEADLOCK;
3639 }
3640
3641 // Set status for the need to update generated fields
3642 50798905 m_update_generated_read_fields = table->has_gcol();
3643
3644
8/27
✓ Branch 0 taken 33158 times.
✓ Branch 1 taken 50765921 times.
✓ Branch 2 taken 33158 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 33158 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 33158 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 33158 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 33158 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 50766180 times.
✗ Branch 26 not taken.
50799079 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, index, result, {
3645 result = index_read_idx_map(buf, index, key, keypart_map, find_flag);
3646 })
3647
4/4
✓ Branch 0 taken 33044825 times.
✓ Branch 1 taken 17754513 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 33044791 times.
50799338 if (!result && m_update_generated_read_fields) {
3648
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 result = update_generated_read_fields(buf, table, index);
3649 34 m_update_generated_read_fields = false;
3650 }
3651 50799338 table->set_row_status_from_handler(result);
3652
2/2
✓ Branch 0 taken 33044832 times.
✓ Branch 1 taken 17754515 times.
50799340 if (likely(!result)) {
3653 33044832 update_index_stats(index);
3654 }
3655 50799356 return result;
3656 50799356 }
3657
3658 /**
3659 Reads the next row via index.
3660
3661 @param[out] buf Row data
3662
3663 @return Operation status.
3664 @retval 0 Success
3665 @retval HA_ERR_END_OF_FILE Row not found
3666 @retval != 0 Error
3667 */
3668
3669 23803110 int handler::ha_index_next(uchar *buf) {
3670 int result;
3671
1/2
✓ Branch 0 taken 23803104 times.
✗ Branch 1 not taken.
23803110 DBUG_TRACE;
3672
3/4
✓ Branch 0 taken 23760233 times.
✓ Branch 1 taken 42871 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23760233 times.
23803104 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3673
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23803104 times.
23803104 assert(inited == INDEX);
3674
3/4
✓ Branch 0 taken 9007 times.
✓ Branch 1 taken 23794097 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9007 times.
23803104 assert(!pushed_idx_cond || buf == table->record[0]);
3675
3676 // Set status for the need to update generated fields
3677 23803104 m_update_generated_read_fields = table->has_gcol();
3678
3679
14/27
✓ Branch 0 taken 18739609 times.
✓ Branch 1 taken 5063495 times.
✓ Branch 2 taken 5795947 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12943662 times.
✓ Branch 5 taken 5795947 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5795935 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 5239268 times.
✓ Branch 10 taken 556667 times.
✓ Branch 11 taken 5239268 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 12943662 times.
✓ Branch 21 taken 12943662 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 12898054 times.
✓ Branch 24 taken 45608 times.
✓ Branch 25 taken 5063493 times.
✗ Branch 26 not taken.
23803104 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result,
3680 { result = index_next(buf); })
3681
4/4
✓ Branch 0 taken 23276786 times.
✓ Branch 1 taken 526304 times.
✓ Branch 2 taken 215589 times.
✓ Branch 3 taken 23061197 times.
23803090 if (!result && m_update_generated_read_fields) {
3682
1/2
✓ Branch 0 taken 215589 times.
✗ Branch 1 not taken.
215589 result = update_generated_read_fields(buf, table, active_index);
3683 215589 m_update_generated_read_fields = false;
3684 }
3685 // Filter duplicate records from multi-value index read.
3686 // (m_unique != nullptr in case of multi-value index read)
3687 // In case of range scan, duplicate records are filtered in
3688 // multi_range_read_next()
3689
6/12
✓ Branch 0 taken 23276786 times.
✓ Branch 1 taken 526304 times.
✓ Branch 2 taken 20585529 times.
✓ Branch 3 taken 2691257 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20585529 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 23803090 times.
23803090 if (!result && !mrr_have_range && m_unique != nullptr && filter_dup_records())
3690 result = HA_ERR_KEY_NOT_FOUND;
3691
3692 23803090 table->set_row_status_from_handler(result);
3693
2/2
✓ Branch 0 taken 23276782 times.
✓ Branch 1 taken 526302 times.
23803088 if (likely(!result)) {
3694 23276782 update_index_stats(active_index);
3695 }
3696
3697
4/6
✓ Branch 0 taken 23606087 times.
✓ Branch 1 taken 196996 times.
✓ Branch 2 taken 23606091 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23606100 times.
✗ Branch 5 not taken.
23803085 DEBUG_SYNC(ha_thd(), "handler_ha_index_next_end");
3698
3699 23803094 return result;
3700 23803096 }
3701
3702 82571715 bool handler::is_using_full_key(key_part_map keypart_map,
3703 uint actual_key_parts) noexcept {
3704
2/2
✓ Branch 0 taken 50665760 times.
✓ Branch 1 taken 31905955 times.
133237475 return (keypart_map == HA_WHOLE_KEY) ||
3705
2/2
✓ Branch 0 taken 21750699 times.
✓ Branch 1 taken 28915061 times.
133237475 (keypart_map == ((key_part_map(1) << actual_key_parts) - 1));
3706 }
3707
3708 82571732 bool handler::is_using_full_unique_key(
3709 uint index, key_part_map keypart_map,
3710 enum ha_rkey_function find_flag) const noexcept {
3711 return (
3712
2/2
✓ Branch 0 taken 43551330 times.
✓ Branch 1 taken 10105449 times.
136228511 is_using_full_key(keypart_map, table->key_info[index].actual_key_parts) &&
3713
2/2
✓ Branch 0 taken 53656779 times.
✓ Branch 1 taken 28915035 times.
136228593 find_flag == HA_READ_KEY_EXACT &&
3714
2/2
✓ Branch 0 taken 11109437 times.
✓ Branch 1 taken 32441893 times.
43551330 (index == table->s->primary_key ||
3715
2/2
✓ Branch 0 taken 6998680 times.
✓ Branch 1 taken 4110757 times.
93681251 (table->key_info[index].flags & HA_NOSAME)));
3716 }
3717
3718 /**
3719 Reads the previous row via index.
3720
3721 @param[out] buf Row data
3722
3723 @return Operation status.
3724 @retval 0 Success
3725 @retval HA_ERR_END_OF_FILE Row not found
3726 @retval != 0 Error
3727 */
3728
3729 19456 int handler::ha_index_prev(uchar *buf) {
3730 int result;
3731
1/2
✓ Branch 0 taken 19456 times.
✗ Branch 1 not taken.
19456 DBUG_TRACE;
3732
3/4
✓ Branch 0 taken 19450 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19450 times.
19456 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19456 times.
19456 assert(inited == INDEX);
3734
3/4
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 19181 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 275 times.
19456 assert(!pushed_idx_cond || buf == table->record[0]);
3735
3736 // Set status for the need to update generated fields
3737 19456 m_update_generated_read_fields = table->has_gcol();
3738
3739
13/27
✓ Branch 0 taken 19450 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 223 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19227 times.
✓ Branch 5 taken 223 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 223 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 223 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 223 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 19227 times.
✓ Branch 21 taken 19227 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 18254 times.
✓ Branch 24 taken 973 times.
✓ Branch 25 taken 6 times.
✗ Branch 26 not taken.
19456 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result,
3740 { result = index_prev(buf); })
3741
4/4
✓ Branch 0 taken 18473 times.
✓ Branch 1 taken 983 times.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 18414 times.
19456 if (!result && m_update_generated_read_fields) {
3742
1/2
✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
59 result = update_generated_read_fields(buf, table, active_index);
3743 59 m_update_generated_read_fields = false;
3744 }
3745 19456 table->set_row_status_from_handler(result);
3746
3747
2/2
✓ Branch 0 taken 18473 times.
✓ Branch 1 taken 983 times.
19456 if (likely(!result)) {
3748 18473 update_index_stats(active_index);
3749 }
3750
3751 19456 return result;
3752 19456 }
3753
3754 /**
3755 Reads the first row via index.
3756
3757 @param[out] buf Row data
3758
3759 @return Operation status.
3760 @retval 0 Success
3761 @retval HA_ERR_END_OF_FILE Row not found
3762 @retval != 0 Error
3763 */
3764
3765 648816 int handler::ha_index_first(uchar *buf) {
3766 int result;
3767
1/2
✓ Branch 0 taken 648951 times.
✗ Branch 1 not taken.
648816 DBUG_TRACE;
3768
3/4
✓ Branch 0 taken 648489 times.
✓ Branch 1 taken 462 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 648489 times.
648951 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 648951 times.
648951 assert(inited == INDEX);
3770
3/4
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 648691 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 260 times.
648951 assert(!pushed_idx_cond || buf == table->record[0]);
3771
3772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 648825 times.
648951 if (is_using_prohibited_gap_locks(table, false)) {
3773 return HA_ERR_LOCK_DEADLOCK;
3774 }
3775
3776 // Set status for the need to update generated fields
3777 648825 m_update_generated_read_fields = table->has_gcol();
3778
3779
18/27
✓ Branch 0 taken 77682 times.
✓ Branch 1 taken 571196 times.
✓ Branch 2 taken 27420 times.
✓ Branch 3 taken 50260 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 27420 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 27419 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 26553 times.
✓ Branch 10 taken 866 times.
✓ Branch 11 taken 26553 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 50260 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 50259 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 47325 times.
✓ Branch 18 taken 2934 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✓ Branch 21 taken 2 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 2 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 571258 times.
✗ Branch 26 not taken.
648878 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result,
3780 { result = index_first(buf); })
3781
4/4
✓ Branch 0 taken 533191 times.
✓ Branch 1 taken 115747 times.
✓ Branch 2 taken 689 times.
✓ Branch 3 taken 532502 times.
648938 if (!result && m_update_generated_read_fields) {
3782
1/2
✓ Branch 0 taken 689 times.
✗ Branch 1 not taken.
689 result = update_generated_read_fields(buf, table, active_index);
3783 689 m_update_generated_read_fields = false;
3784 }
3785 // Filter duplicate records from multi-value index read.
3786 // (m_unique != nullptr in case of multi-value index read)
3787 // In case of range scan, duplicate records are filtered in
3788 // multi_range_read_next()
3789
6/12
✓ Branch 0 taken 533194 times.
✓ Branch 1 taken 115744 times.
✓ Branch 2 taken 530009 times.
✓ Branch 3 taken 3185 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 530009 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 648938 times.
648938 if (!result && !mrr_have_range && m_unique != nullptr && filter_dup_records())
3790 result = HA_ERR_KEY_NOT_FOUND;
3791
3792 648938 table->set_row_status_from_handler(result);
3793
3794
2/2
✓ Branch 0 taken 533200 times.
✓ Branch 1 taken 115749 times.
648948 if (likely(!result)) {
3795 533200 update_index_stats(active_index);
3796 }
3797
3798 648945 return result;
3799 648945 }
3800
3801 /**
3802 Reads the last row via index.
3803
3804 @param[out] buf Row data
3805
3806 @return Operation status.
3807 @retval 0 Success
3808 @retval HA_ERR_END_OF_FILE Row not found
3809 @retval != 0 Error
3810 */
3811
3812 5417 int handler::ha_index_last(uchar *buf) {
3813 int result;
3814
1/2
✓ Branch 0 taken 5417 times.
✗ Branch 1 not taken.
5417 DBUG_TRACE;
3815
3/4
✓ Branch 0 taken 5415 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5415 times.
5417 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5417 times.
5417 assert(inited == INDEX);
3817
3/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 5362 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 55 times.
5417 assert(!pushed_idx_cond || buf == table->record[0]);
3818
3819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5417 times.
5417 if (is_using_prohibited_gap_locks(table, false)) {
3820 return HA_ERR_LOCK_DEADLOCK;
3821 }
3822
3823 // Set status for the need to update generated fields
3824 5417 m_update_generated_read_fields = table->has_gcol();
3825
3826
13/27
✓ Branch 0 taken 5409 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 3493 times.
✓ Branch 3 taken 1916 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3493 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3493 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3493 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3493 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1916 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 1916 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 1902 times.
✓ Branch 18 taken 14 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 8 times.
✗ Branch 26 not taken.
5417 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result,
3827 { result = index_last(buf); })
3828
4/4
✓ Branch 0 taken 5296 times.
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 5272 times.
5417 if (!result && m_update_generated_read_fields) {
3829
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 result = update_generated_read_fields(buf, table, active_index);
3830 24 m_update_generated_read_fields = false;
3831 }
3832 5417 table->set_row_status_from_handler(result);
3833
3834
2/2
✓ Branch 0 taken 5296 times.
✓ Branch 1 taken 121 times.
5417 if (likely(!result)) {
3835 5296 update_index_stats(active_index);
3836 }
3837
3838 5417 return result;
3839 5417 }
3840
3841 /**
3842 Reads the next same row via index.
3843
3844 @param[out] buf Row data
3845 @param key Key to search for
3846 @param keylen Length of key
3847
3848 @return Operation status.
3849 @retval 0 Success
3850 @retval HA_ERR_END_OF_FILE Row not found
3851 @retval != 0 Error
3852 */
3853
3854 102627778 int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen) {
3855 int result;
3856
1/2
✓ Branch 0 taken 102627807 times.
✗ Branch 1 not taken.
102627778 DBUG_TRACE;
3857
3/4
✓ Branch 0 taken 102557737 times.
✓ Branch 1 taken 70070 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 102557737 times.
102627807 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
3858
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102627807 times.
102627807 assert(inited == INDEX);
3859
3/4
✓ Branch 0 taken 1106974 times.
✓ Branch 1 taken 101520833 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1106974 times.
102627807 assert(!pushed_idx_cond || buf == table->record[0]);
3860
3861 // Set status for the need to update generated fields
3862 102627807 m_update_generated_read_fields = table->has_gcol();
3863
14/27
✓ Branch 0 taken 3612952 times.
✓ Branch 1 taken 99014858 times.
✓ Branch 2 taken 585902 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3027050 times.
✓ Branch 5 taken 585902 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 585902 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 585901 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 585901 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 3027050 times.
✓ Branch 21 taken 3027050 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 1942391 times.
✓ Branch 24 taken 1084659 times.
✓ Branch 25 taken 99014820 times.
✗ Branch 26 not taken.
102627810 MYSQL_TABLE_IO_WAIT(PSI_TABLE_FETCH_ROW, active_index, result,
3864 { result = index_next_same(buf, key, keylen); })
3865
4/4
✓ Branch 0 taken 84660607 times.
✓ Branch 1 taken 17967165 times.
✓ Branch 2 taken 1278 times.
✓ Branch 3 taken 84659329 times.
102627772 if (!result && m_update_generated_read_fields) {
3866
1/2
✓ Branch 0 taken 1278 times.
✗ Branch 1 not taken.
1278 result = update_generated_read_fields(buf, table, active_index);
3867 1278 m_update_generated_read_fields = false;
3868 }
3869 // Filter duplicate records from multi-value index read.
3870 // (m_unique != nullptr in case of multi-value index read)
3871 // In case of range scan, duplicate records are filtered in
3872 // multi_range_read_next()
3873
3874
8/8
✓ Branch 0 taken 84660615 times.
✓ Branch 1 taken 17967157 times.
✓ Branch 2 taken 84253108 times.
✓ Branch 3 taken 407507 times.
✓ Branch 4 taken 130 times.
✓ Branch 5 taken 84252978 times.
✓ Branch 6 taken 44 times.
✓ Branch 7 taken 102627728 times.
102627902 if (!result && !mrr_have_range && m_unique != nullptr &&
3875
3/4
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 86 times.
130 filter_dup_records()) {
3876 44 result = HA_ERR_KEY_NOT_FOUND;
3877 }
3878
3879 102627772 table->set_row_status_from_handler(result);
3880
3881
2/2
✓ Branch 0 taken 84660570 times.
✓ Branch 1 taken 17967223 times.
102627796 if (likely(!result)) {
3882 84660570 update_index_stats(active_index);
3883 }
3884
3885 102627801 return result;
3886 102627794 }
3887
3888 /**
3889 Read first row (only) from a table.
3890
3891 This is never called for tables whose storage engine do not contain exact
3892 statistics on number of records, e.g. InnoDB.
3893
3894 @note Since there is only one implementation for this function, it is
3895 non-virtual and does not call a protected inner function, like
3896 most other handler functions.
3897
3898 @note Implementation only calls other handler functions, so there is no need
3899 to update generated columns nor set table status.
3900 */
3901 int handler::ha_read_first_row(uchar *buf, uint primary_key) {
3902 int error;
3903 DBUG_TRACE;
3904
3905 ha_statistic_increment(&System_status_var::ha_read_first_count);
3906
3907 /*
3908 If there is very few deleted rows in the table, find the first row by
3909 scanning the table.
3910 TODO remove the test for HA_READ_ORDER
3911 */
3912 if (stats.deleted < 10 || primary_key >= MAX_KEY ||
3913 !(index_flags(primary_key, 0, false) & HA_READ_ORDER)) {
3914 if (!(error = ha_rnd_init(true))) {
3915 while ((error = ha_rnd_next(buf)) == HA_ERR_RECORD_DELETED)
3916 /* skip deleted row */;
3917 const int end_error = ha_rnd_end();
3918 if (!error) error = end_error;
3919 }
3920 } else {
3921 /* Find the first row through the primary key */
3922 if (!(error = ha_index_init(primary_key, false))) {
3923 error = ha_index_first(buf);
3924 const int end_error = ha_index_end();
3925 if (!error) error = end_error;
3926 }
3927 }
3928 return error;
3929 }
3930
3931 int handler::ha_index_read_pushed(uchar *buf, const uchar *key,
3932 key_part_map keypart_map) {
3933 DBUG_TRACE;
3934
3935 // Set status for the need to update generated fields
3936 m_update_generated_read_fields = table->has_gcol();
3937
3938 int result = index_read_pushed(buf, key, keypart_map);
3939 if (!result && m_update_generated_read_fields) {
3940 result = update_generated_read_fields(buf, table, active_index);
3941 m_update_generated_read_fields = false;
3942 }
3943 table->set_row_status_from_handler(result);
3944 return result;
3945 }
3946
3947 int handler::ha_index_next_pushed(uchar *buf) {
3948 DBUG_TRACE;
3949
3950 // Set status for the need to update generated fields
3951 m_update_generated_read_fields = table->has_gcol();
3952
3953 int result = index_next_pushed(buf);
3954 if (!result && m_update_generated_read_fields) {
3955 result = update_generated_read_fields(buf, table, active_index);
3956 m_update_generated_read_fields = false;
3957 }
3958 table->set_row_status_from_handler(result);
3959 return result;
3960 }
3961
3962 /**
3963 Generate the next auto-increment number based on increment and offset.
3964 computes the lowest number
3965 - strictly greater than "nr"
3966 - of the form: auto_increment_offset + N * auto_increment_increment
3967 If overflow happened then return MAX_ULONGLONG value as an
3968 indication of overflow.
3969 In most cases increment= offset= 1, in which case we get:
3970 @verbatim 1,2,3,4,5,... @endverbatim
3971 If increment=10 and offset=5 and previous number is 1, we get:
3972 @verbatim 1,5,15,25,35,... @endverbatim
3973 */
3974 20752443 inline ulonglong compute_next_insert_id(ulonglong nr,
3975 struct System_variables *variables) {
3976 20752443 const ulonglong save_nr = nr;
3977
3978
2/2
✓ Branch 0 taken 20308316 times.
✓ Branch 1 taken 444127 times.
20752443 if (variables->auto_increment_increment == 1)
3979 20308316 nr = nr + 1; // optimization of the formula below
3980 else {
3981 444127 nr = (((nr + variables->auto_increment_increment -
3982 444127 variables->auto_increment_offset)) /
3983 444127 (ulonglong)variables->auto_increment_increment);
3984 444127 nr = (nr * (ulonglong)variables->auto_increment_increment +
3985 444127 variables->auto_increment_offset);
3986 }
3987
3988
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 20752446 times.
20752443 if (unlikely(nr <= save_nr)) return ULLONG_MAX;
3989
3990 20752446 return nr;
3991 }
3992
3993 1736611 void handler::adjust_next_insert_id_after_explicit_value(ulonglong nr) {
3994 /*
3995 If we have set THD::next_insert_id previously and plan to insert an
3996 explicitely-specified value larger than this, we need to increase
3997 THD::next_insert_id to be greater than the explicit value.
3998 */
3999
4/4
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 1736280 times.
✓ Branch 2 taken 266 times.
✓ Branch 3 taken 65 times.
1736611 if ((next_insert_id > 0) && (nr >= next_insert_id))
4000 266 set_next_insert_id(compute_next_insert_id(nr, &table->in_use->variables));
4001 1736611 }
4002
4003 /** @brief
4004 Computes the largest number X:
4005 - smaller than or equal to "nr"
4006 - of the form: auto_increment_offset + N * auto_increment_increment
4007 where N>=0.
4008
4009 SYNOPSIS
4010 prev_insert_id
4011 nr Number to "round down"
4012 variables variables struct containing auto_increment_increment and
4013 auto_increment_offset
4014
4015 RETURN
4016 The number X if it exists, "nr" otherwise.
4017 */
4018 19 inline ulonglong prev_insert_id(ulonglong nr,
4019 struct System_variables *variables) {
4020
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 13 times.
19 if (unlikely(nr < variables->auto_increment_offset)) {
4021 /*
4022 There's nothing good we can do here. That is a pathological case, where
4023 the offset is larger than the column's max possible value, i.e. not even
4024 the first sequence value may be inserted. User will receive warning.
4025 */
4026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 DBUG_PRINT("info", ("auto_increment: nr: %lu cannot honour "
4027 "auto_increment_offset: %lu",
4028 (ulong)nr, variables->auto_increment_offset));
4029 6 return nr;
4030 }
4031
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (variables->auto_increment_increment == 1)
4032 7 return nr; // optimization of the formula below
4033 6 nr = (((nr - variables->auto_increment_offset)) /
4034 6 (ulonglong)variables->auto_increment_increment);
4035 6 return (nr * (ulonglong)variables->auto_increment_increment +
4036 6 variables->auto_increment_offset);
4037 }
4038
4039 /**
4040 Update the auto_increment field if necessary.
4041
4042 Updates columns with type NEXT_NUMBER if:
4043
4044 - If column value is set to NULL (in which case
4045 autoinc_field_has_explicit_non_null_value is 0)
4046 - If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not
4047 set. In the future we will only set NEXT_NUMBER fields if one sets them
4048 to NULL (or they are not included in the insert list).
4049
4050 In those cases, we check if the currently reserved interval still has
4051 values we have not used. If yes, we pick the smallest one and use it.
4052 Otherwise:
4053
4054 - If a list of intervals has been provided to the statement via SET
4055 INSERT_ID or via an Intvar_log_event (in a replication slave), we pick the
4056 first unused interval from this list, consider it as reserved.
4057
4058 - Otherwise we set the column for the first row to the value
4059 next_insert_id(get_auto_increment(column))) which is usually
4060 max-used-column-value+1.
4061 We call get_auto_increment() for the first row in a multi-row
4062 statement. get_auto_increment() will tell us the interval of values it
4063 reserved for us.
4064
4065 - In both cases, for the following rows we use those reserved values without
4066 calling the handler again (we just progress in the interval, computing
4067 each new value from the previous one). Until we have exhausted them, then
4068 we either take the next provided interval or call get_auto_increment()
4069 again to reserve a new interval.
4070
4071 - In both cases, the reserved intervals are remembered in
4072 thd->auto_inc_intervals_in_cur_stmt_for_binlog if statement-based
4073 binlogging; the last reserved interval is remembered in
4074 auto_inc_interval_for_cur_row. The number of reserved intervals is
4075 remembered in auto_inc_intervals_count. It differs from the number of
4076 elements in thd->auto_inc_intervals_in_cur_stmt_for_binlog() because the
4077 latter list is cumulative over all statements forming one binlog event
4078 (when stored functions and triggers are used), and collapses two
4079 contiguous intervals in one (see its append() method).
4080
4081 The idea is that generated auto_increment values are predictable and
4082 independent of the column values in the table. This is needed to be
4083 able to replicate into a table that already has rows with a higher
4084 auto-increment value than the one that is inserted.
4085
4086 After we have already generated an auto-increment number and the user
4087 inserts a column with a higher value than the last used one, we will
4088 start counting from the inserted value.
4089
4090 This function's "outputs" are: the table's auto_increment field is filled
4091 with a value, thd->next_insert_id is filled with the value to use for the
4092 next row, if a value was autogenerated for the current row it is stored in
4093 thd->insert_id_for_cur_row, if get_auto_increment() was called
4094 thd->auto_inc_interval_for_cur_row is modified, if that interval is not
4095 present in thd->auto_inc_intervals_in_cur_stmt_for_binlog it is added to
4096 this list.
4097
4098 @todo
4099 Replace all references to "next number" or NEXT_NUMBER to
4100 "auto_increment", everywhere (see below: there is
4101 table->autoinc_field_has_explicit_non_null_value, and there also exists
4102 table->next_number_field, it's not consistent).
4103
4104 @retval
4105 0 ok
4106 @retval
4107 HA_ERR_AUTOINC_READ_FAILED get_auto_increment() was called and
4108 returned ~(ulonglong) 0
4109 @retval
4110 HA_ERR_AUTOINC_ERANGE storing value in field caused strict mode
4111 failure.
4112 */
4113
4114 #define AUTO_INC_DEFAULT_NB_ROWS 1 // Some prefer 1024 here
4115 #define AUTO_INC_DEFAULT_NB_MAX_BITS 16
4116 #define AUTO_INC_DEFAULT_NB_MAX ((1 << AUTO_INC_DEFAULT_NB_MAX_BITS) - 1)
4117
4118 15413932 int handler::update_auto_increment() {
4119 15413932 ulonglong nr, nb_reserved_values = 0;
4120 15413932 bool append = false;
4121 15413932 THD *thd = table->in_use;
4122 15413932 struct System_variables *variables = &thd->variables;
4123
3/4
✓ Branch 0 taken 13612888 times.
✓ Branch 1 taken 1801044 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13612888 times.
15413932 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
4124
1/2
✓ Branch 0 taken 15414223 times.
✗ Branch 1 not taken.
15413932 DBUG_TRACE;
4125
4126 /*
4127 next_insert_id is a "cursor" into the reserved interval, it may go greater
4128 than the interval, but not smaller.
4129 */
4130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15414169 times.
15414223 assert(next_insert_id >= auto_inc_interval_for_cur_row.minimum());
4131
4132
5/6
✓ Branch 0 taken 15414240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13677337 times.
✓ Branch 3 taken 1736903 times.
✓ Branch 4 taken 1736938 times.
✓ Branch 5 taken 13677302 times.
29091506 if ((nr = table->next_number_field->val_int()) != 0 ||
4133
2/2
✓ Branch 0 taken 6549342 times.
✓ Branch 1 taken 7127995 times.
13677337 (table->autoinc_field_has_explicit_non_null_value &&
4134
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 6549255 times.
6549342 thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)) {
4135 /*
4136 First test if the query was aborted due to strict mode constraints.
4137 */
4138
7/8
✓ Branch 0 taken 1736981 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1736979 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1736984 times.
1736945 if (thd->is_error() &&
4139 2 thd->get_stmt_da()->mysql_errno() == ER_TRUNCATED_WRONG_VALUE)
4140 2 return HA_ERR_AUTOINC_ERANGE;
4141
4142 /*
4143 Update next_insert_id if we had already generated a value in this
4144 statement (case of INSERT VALUES(null),(3763),(null):
4145 the last NULL needs to insert 3764, not the value of the first NULL plus
4146 1).
4147 Also we should take into account the the sign of the value.
4148 Since auto_increment value can't have negative value we should update
4149 next_insert_id only in case when we INSERTing explicit positive value.
4150 It means that for a table that has SIGNED INTEGER column when we execute
4151 the following statement
4152 INSERT INTO t1 VALUES( NULL), (-1), (NULL)
4153 we shouldn't call adjust_next_insert_id_after_explicit_value()
4154 and the result row will be (1, -1, 2) (for new opened connection
4155 to the server). On the other hand, for the statement
4156 INSERT INTO t1 VALUES( NULL), (333), (NULL)
4157 we should call adjust_next_insert_id_after_explicit_value()
4158 and result row will be (1, 333, 334).
4159 */
4160
7/8
✓ Branch 0 taken 1736893 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1355913 times.
✓ Branch 3 taken 380980 times.
✓ Branch 4 taken 1355701 times.
✓ Branch 5 taken 212 times.
✓ Branch 6 taken 1736721 times.
✓ Branch 7 taken 172 times.
1736984 if (table->next_number_field->is_unsigned() || ((longlong)nr) > 0)
4161
1/2
✓ Branch 0 taken 1736662 times.
✗ Branch 1 not taken.
1736721 adjust_next_insert_id_after_explicit_value(nr);
4162
4163 1736834 insert_id_for_cur_row = 0; // didn't generate anything
4164 1736834 return 0;
4165 }
4166
4167
3/4
✓ Branch 0 taken 13677217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 13677213 times.
13677302 if (next_insert_id > table->next_number_field->get_max_int_value())
4168 4 return HA_ERR_AUTOINC_READ_FAILED;
4169
4170
2/2
✓ Branch 0 taken 7113025 times.
✓ Branch 1 taken 6564256 times.
13677213 if ((nr = next_insert_id) >= auto_inc_interval_for_cur_row.maximum()) {
4171 /* next_insert_id is beyond what is reserved, so we reserve more. */
4172 7113025 const Discrete_interval *forced = thd->auto_inc_intervals_forced.get_next();
4173
2/2
✓ Branch 0 taken 37953 times.
✓ Branch 1 taken 7075066 times.
7113019 if (forced != nullptr) {
4174 37953 nr = forced->minimum();
4175 /*
4176 In a multi insert statement when the number of affected rows is known
4177 then reserve those many number of auto increment values. So that
4178 interval will be starting value to starting value + number of affected
4179 rows * increment of auto increment.
4180 */
4181 37959 nb_reserved_values = (estimation_rows_to_insert > 0)
4182
2/2
✓ Branch 0 taken 37768 times.
✓ Branch 1 taken 191 times.
37959 ? estimation_rows_to_insert
4183 191 : forced->values();
4184 } else {
4185 /*
4186 handler::estimation_rows_to_insert was set by
4187 handler::ha_start_bulk_insert(); if 0 it means "unknown".
4188 */
4189 ulonglong nb_desired_values;
4190 /*
4191 If an estimation was given to the engine:
4192 - use it.
4193 - if we already reserved numbers, it means the estimation was
4194 not accurate, then we'll reserve 2*AUTO_INC_DEFAULT_NB_ROWS the 2nd
4195 time, twice that the 3rd time etc.
4196 If no estimation was given, use those increasing defaults from the
4197 start, starting from AUTO_INC_DEFAULT_NB_ROWS.
4198 Don't go beyond a max to not reserve "way too much" (because
4199 reservation means potentially losing unused values).
4200 Note that in prelocked mode no estimation is given.
4201 */
4202
4203
4/4
✓ Branch 0 taken 7040701 times.
✓ Branch 1 taken 34365 times.
✓ Branch 2 taken 514077 times.
✓ Branch 3 taken 6526624 times.
7075066 if ((auto_inc_intervals_count == 0) && (estimation_rows_to_insert > 0))
4204 514077 nb_desired_values = estimation_rows_to_insert;
4205
2/2
✓ Branch 0 taken 6526621 times.
✓ Branch 1 taken 34368 times.
6560989 else if ((auto_inc_intervals_count == 0) &&
4206
2/2
✓ Branch 0 taken 3263 times.
✓ Branch 1 taken 6523358 times.
6526621 (thd->lex->bulk_insert_row_cnt > 0)) {
4207 /*
4208 For multi-row inserts, if the bulk inserts cannot be started, the
4209 handler::estimation_rows_to_insert will not be set. But we still
4210 want to reserve the autoinc values.
4211 */
4212 3263 nb_desired_values = thd->lex->bulk_insert_row_cnt;
4213 } else /* go with the increasing defaults */
4214 {
4215 /* avoid overflow in formula, with this if() */
4216
2/2
✓ Branch 0 taken 6557688 times.
✓ Branch 1 taken 38 times.
6557726 if (auto_inc_intervals_count <= AUTO_INC_DEFAULT_NB_MAX_BITS) {
4217 6557688 nb_desired_values =
4218 6557688 AUTO_INC_DEFAULT_NB_ROWS * (1 << auto_inc_intervals_count);
4219 6557687 nb_desired_values =
4220 6557688 std::min(nb_desired_values, ulonglong(AUTO_INC_DEFAULT_NB_MAX));
4221 } else
4222 38 nb_desired_values = AUTO_INC_DEFAULT_NB_MAX;
4223 }
4224 /* This call ignores all its parameters but nr, currently */
4225 7075065 get_auto_increment(variables->auto_increment_offset,
4226
1/2
✓ Branch 0 taken 7075080 times.
✗ Branch 1 not taken.
7075065 variables->auto_increment_increment, nb_desired_values,
4227 &nr, &nb_reserved_values);
4228
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7075066 times.
7075080 if (nr == ULLONG_MAX) return HA_ERR_AUTOINC_READ_FAILED; // Mark failure
4229
4230 /*
4231 That rounding below should not be needed when all engines actually
4232 respect offset and increment in get_auto_increment(). But they don't
4233 so we still do it. Wonder if for the not-first-in-index we should do
4234 it. Hope that this rounding didn't push us out of the interval; even
4235 if it did we cannot do anything about it (calling the engine again
4236 will not help as we inserted no row).
4237 */
4238 7075066 nr = compute_next_insert_id(nr - 1, variables);
4239 }
4240
4241
2/2
✓ Branch 0 taken 7112915 times.
✓ Branch 1 taken 34 times.
7112949 if (table->s->next_number_keypart == 0) {
4242 /* We must defer the appending until "nr" has been possibly truncated */
4243 7112915 append = true;
4244 } else {
4245 /*
4246 For such auto_increment there is no notion of interval, just a
4247 singleton. The interval is not even stored in
4248 thd->auto_inc_interval_for_cur_row, so we are sure to call the engine
4249 for next row.
4250 */
4251
3/8
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
34 DBUG_PRINT("info", ("auto_increment: special not-first-in-index"));
4252 }
4253 }
4254
4255
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 13677268 times.
13677213 if (unlikely(nr == ULLONG_MAX)) return HA_ERR_AUTOINC_ERANGE;
4256
4257
5/8
✓ Branch 0 taken 13677275 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13677292 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 415 times.
✓ Branch 5 taken 13676877 times.
✓ Branch 6 taken 415 times.
✗ Branch 7 not taken.
13677268 DBUG_PRINT("info", ("auto_increment: %lu", (ulong)nr));
4258
4259
3/4
✓ Branch 0 taken 13677256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 13677199 times.
13677292 if (unlikely(table->next_number_field->store((longlong)nr, true))) {
4260 /*
4261 first test if the query was aborted due to strict mode constraints
4262 */
4263
6/8
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19 times.
✓ Branch 7 taken 19 times.
57 if (thd->is_error() &&
4264 19 thd->get_stmt_da()->mysql_errno() == ER_WARN_DATA_OUT_OF_RANGE)
4265 19 return HA_ERR_AUTOINC_ERANGE;
4266
4267 /*
4268 field refused this value (overflow) and truncated it, use the result of
4269 the truncation (which is going to be inserted); however we try to
4270 decrease it to honour auto_increment_* variables.
4271 That will shift the left bound of the reserved interval, we don't
4272 bother shifting the right bound (anyway any other value from this
4273 interval will cause a duplicate key).
4274 */
4275
2/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
19 nr = prev_insert_id(table->next_number_field->val_int(), variables);
4276
2/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
19 if (unlikely(table->next_number_field->store((longlong)nr, true)))
4277 nr = table->next_number_field->val_int();
4278 }
4279
2/2
✓ Branch 0 taken 7112855 times.
✓ Branch 1 taken 6564363 times.
13677218 if (append) {
4280 7112855 auto_inc_interval_for_cur_row.replace(nr, nb_reserved_values,
4281 7112855 variables->auto_increment_increment);
4282 7112889 auto_inc_intervals_count++;
4283 /* Row-based replication does not need to store intervals in binlog */
4284 #ifdef WITH_WSREP
4285
15/16
✓ Branch 0 taken 7112893 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3924357 times.
✓ Branch 3 taken 3188536 times.
✓ Branch 4 taken 141005 times.
✓ Branch 5 taken 3783352 times.
✓ Branch 6 taken 76692 times.
✓ Branch 7 taken 64313 times.
✓ Branch 8 taken 76261 times.
✓ Branch 9 taken 431 times.
✓ Branch 10 taken 2307360 times.
✓ Branch 11 taken 4805119 times.
✓ Branch 12 taken 1800805 times.
✓ Branch 13 taken 506997 times.
✓ Branch 14 taken 1800805 times.
✓ Branch 15 taken 5312116 times.
9420691 if (((WSREP_EMULATE_BINLOG(thd)) || mysql_bin_log.is_open()) &&
4286 2307791 !thd->is_current_stmt_binlog_format_row())
4287 #else
4288 if (mysql_bin_log.is_open() && !thd->is_current_stmt_binlog_format_row())
4289 #endif /* WITH_WSREP */
4290
1/2
✓ Branch 0 taken 1800805 times.
✗ Branch 1 not taken.
1800804 thd->auto_inc_intervals_in_cur_stmt_for_binlog.append(
4291 auto_inc_interval_for_cur_row.minimum(),
4292 auto_inc_interval_for_cur_row.values(),
4293 1800805 variables->auto_increment_increment);
4294 }
4295
4296 /*
4297 Record this autogenerated value. If the caller then
4298 succeeds to insert this value, it will call
4299 record_first_successful_insert_id_in_cur_stmt()
4300 which will set first_successful_insert_id_in_cur_stmt if it's not
4301 already set.
4302 */
4303 13677284 insert_id_for_cur_row = nr;
4304 /*
4305 Set next insert id to point to next auto-increment value to be able to
4306 handle multi-row statements.
4307 */
4308
1/2
✓ Branch 0 taken 13677277 times.
✗ Branch 1 not taken.
13677284 set_next_insert_id(compute_next_insert_id(nr, variables));
4309
4310 13677277 return 0;
4311 15414154 }
4312
4313 /** @brief
4314 MySQL signal that it changed the column bitmap
4315
4316 USAGE
4317 This is for handlers that needs to setup their own column bitmaps.
4318 Normally the handler should set up their own column bitmaps in
4319 index_init() or rnd_init() and in any column_bitmaps_signal() call after
4320 this.
4321
4322 The handler is allowed to do changes to the bitmap after an index_init or
4323 rnd_init() call is made as after this, MySQL will not use the bitmap
4324 for any program logic checking.
4325 */
4326 223299924 void handler::column_bitmaps_signal() {
4327
1/2
✓ Branch 0 taken 223302041 times.
✗ Branch 1 not taken.
223299924 DBUG_TRACE;
4328
5/8
✓ Branch 0 taken 223301868 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 223301911 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12808 times.
✓ Branch 5 taken 223289103 times.
✓ Branch 6 taken 12808 times.
✗ Branch 7 not taken.
223302041 DBUG_PRINT("info", ("read_set: %p write_set: %p", table->read_set,
4329 table->write_set));
4330 223301911 }
4331
4332 /**
4333 Reserves an interval of auto_increment values from the handler.
4334
4335 @param offset offset (modulus increment)
4336 @param increment increment between calls
4337 @param nb_desired_values how many values we want
4338 @param[out] first_value the first value reserved by the handler
4339 @param[out] nb_reserved_values how many values the handler reserved
4340
4341 offset and increment means that we want values to be of the form
4342 offset + N * increment, where N>=0 is integer.
4343 If the function sets *first_value to ULLONG_MAX it means an error.
4344 If the function sets *nb_reserved_values to ULLONG_MAX it means it has
4345 reserved to "positive infinite".
4346 */
4347
4348 3 void handler::get_auto_increment(ulonglong offset [[maybe_unused]],
4349 ulonglong increment [[maybe_unused]],
4350 ulonglong nb_desired_values [[maybe_unused]],
4351 ulonglong *first_value,
4352 ulonglong *nb_reserved_values) {
4353 ulonglong nr;
4354 int error;
4355
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 DBUG_TRACE;
4356
4357
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 (void)extra(HA_EXTRA_KEYREAD);
4358 3 table->mark_columns_used_by_index_no_reset(table->s->next_number_index,
4359
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 table->read_set);
4360
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 column_bitmaps_signal();
4361
4362
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (ha_index_init(table->s->next_number_index, true)) {
4363 /* This should never happen, assert in debug, and fail in release build */
4364 assert(0);
4365 *first_value = ULLONG_MAX;
4366 return;
4367 }
4368
4369
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (table->s->next_number_keypart == 0) { // Autoincrement at key-start
4370
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 error = ha_index_last(table->record[1]);
4371 /*
4372 MySQL implicitly assumes such method does locking (as MySQL decides to
4373 use nr+increment without checking again with the handler, in
4374 handler::update_auto_increment()), so reserves to infinite.
4375 */
4376 3 *nb_reserved_values = ULLONG_MAX;
4377 } else {
4378 uchar key[MAX_KEY_LENGTH];
4379 key_copy(key, table->record[0],
4380 table->key_info + table->s->next_number_index,
4381 table->s->next_number_key_offset);
4382 error =
4383 ha_index_read_map(table->record[1], key,
4384 make_prev_keypart_map(table->s->next_number_keypart),
4385 HA_READ_PREFIX_LAST);
4386 /*
4387 MySQL needs to call us for next row: assume we are inserting ("a",null)
4388 here, we return 3, and next this statement will want to insert
4389 ("b",null): there is no reason why ("b",3+1) would be the good row to
4390 insert: maybe it already exists, maybe 3+1 is too large...
4391 */
4392 *nb_reserved_values = 1;
4393 }
4394
4395
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (error) {
4396
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3 if (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND) {
4397 /* No entry found, start with 1. */
4398 3 nr = 1;
4399 } else {
4400 assert(0);
4401 nr = ULLONG_MAX;
4402 }
4403 } else
4404 nr = ((ulonglong)table->next_number_field->val_int_offset(
4405 table->s->rec_buff_length) +
4406 1);
4407
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 ha_index_end();
4408
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 (void)extra(HA_EXTRA_NO_KEYREAD);
4409 3 *first_value = nr;
4410
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 }
4411
4412 18208947 void handler::ha_release_auto_increment() {
4413
6/8
✓ Branch 0 taken 18056285 times.
✓ Branch 1 taken 152662 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 18056263 times.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 22 times.
✗ Branch 7 not taken.
18208947 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK ||
4414 (!next_insert_id && !insert_id_for_cur_row));
4415
2/2
✓ Branch 0 taken 14608526 times.
✓ Branch 1 taken 3600545 times.
18208947 DEBUG_SYNC(ha_thd(), "release_auto_increment");
4416 18209350 release_auto_increment();
4417 18209180 insert_id_for_cur_row = 0;
4418 18209180 auto_inc_interval_for_cur_row.replace(0, 0, 0);
4419 18209216 auto_inc_intervals_count = 0;
4420
2/2
✓ Branch 0 taken 7078650 times.
✓ Branch 1 taken 11130566 times.
18209216 if (next_insert_id > 0) {
4421 7078650 next_insert_id = 0;
4422 /*
4423 this statement used forced auto_increment values if there were some,
4424 wipe them away for other statements.
4425 */
4426 7078650 table->in_use->auto_inc_intervals_forced.clear();
4427 }
4428 18209222 }
4429
4430 1974641 const char *table_case_name(const HA_CREATE_INFO *info, const char *name) {
4431
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1974641 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1974641 return ((lower_case_table_names == 2 && info->alias) ? info->alias : name);
4432 }
4433
4434 /**
4435 Construct and emit duplicate key error message using information
4436 from table's record buffer.
4437
4438 @param table TABLE object which record buffer should be used as
4439 source for column values.
4440 @param key Key description.
4441 @param msg Error message template to which key value should be
4442 added.
4443 @param errflag Flags for my_error() call.
4444 @param org_table_name The original table name (if any)
4445 */
4446
4447 257091 void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag,
4448 const char *org_table_name) {
4449 /* Write the duplicated key in the error message */
4450 char key_buff[MAX_KEY_LENGTH];
4451 257091 String str(key_buff, sizeof(key_buff), system_charset_info);
4452 257091 std::string key_name;
4453
4454
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 257090 times.
257091 if (key == nullptr) {
4455 /* Key is unknown */
4456
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 key_name = "*UNKNOWN*";
4457
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 str.copy("", 0, system_charset_info);
4458
4459 } else {
4460 /* Table is opened and defined at this point */
4461
1/2
✓ Branch 0 taken 257090 times.
✗ Branch 1 not taken.
257090 key_unpack(&str, table, key);
4462 257090 size_t max_length = MYSQL_ERRMSG_SIZE - strlen(msg);
4463
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 257087 times.
257090 if (str.length() >= max_length) {
4464 3 str.length(max_length - 4);
4465
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 str.append(STRING_WITH_LEN("..."));
4466 }
4467 257090 str[str.length()] = 0;
4468
2/2
✓ Branch 0 taken 1278 times.
✓ Branch 1 taken 255812 times.
257090 if (org_table_name != nullptr)
4469
1/2
✓ Branch 0 taken 1278 times.
✗ Branch 1 not taken.
1278 key_name = org_table_name;
4470 else
4471
1/2
✓ Branch 0 taken 255812 times.
✗ Branch 1 not taken.
255812 key_name = table->s->table_name.str;
4472
1/2
✓ Branch 0 taken 257090 times.
✗ Branch 1 not taken.
257090 key_name += ".";
4473
4474
1/2
✓ Branch 0 taken 257090 times.
✗ Branch 1 not taken.
257090 key_name += key->name;
4475 }
4476
4477
2/4
✓ Branch 0 taken 257091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 257091 times.
✗ Branch 3 not taken.
257091 my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr(), key_name.c_str());
4478 257091 }
4479
4480 /**
4481 Construct and emit duplicate key error message using information
4482 from table's record buffer.
4483
4484 @sa print_keydup_error(table, key, msg, errflag).
4485 */
4486
4487 256256 void print_keydup_error(TABLE *table, KEY *key, myf errflag,
4488 const char *org_table_name) {
4489 256256 print_keydup_error(table, key,
4490 256256 ER_THD(current_thd, ER_DUP_ENTRY_WITH_KEY_NAME), errflag,
4491 org_table_name);
4492 256256 }
4493
4494 /**
4495 This method is used to analyse the error to see whether the error
4496 is ignorable or not. Further comments in header file.
4497 */
4498
4499 4457369 bool handler::is_ignorable_error(int error) {
4500
1/2
✓ Branch 0 taken 4457369 times.
✗ Branch 1 not taken.
4457369 DBUG_TRACE;
4501
4502 // Catch errors that are ignorable
4503
2/2
✓ Branch 0 taken 4456575 times.
✓ Branch 1 taken 794 times.
4457369 switch (error) {
4504 // Error code 0 is not an error.
4505 4456575 case 0:
4506 // Dup key errors may be explicitly ignored.
4507 case HA_ERR_FOUND_DUPP_KEY:
4508 case HA_ERR_FOUND_DUPP_UNIQUE:
4509 // Foreign key constraint violations are ignorable.
4510 case HA_ERR_ROW_IS_REFERENCED:
4511 case HA_ERR_NO_REFERENCED_ROW:
4512 4456575 return true;
4513 }
4514
4515 // Default is that an error is not ignorable.
4516 794 return false;
4517 4457369 }
4518
4519 /**
4520 This method is used to analyse the error to see whether the error
4521 is fatal or not. Further comments in header file.
4522 */
4523
4524 256639 bool handler::is_fatal_error(int error) {
4525
1/2
✓ Branch 0 taken 256639 times.
✗ Branch 1 not taken.
256639 DBUG_TRACE;
4526
4527 // No ignorable errors are fatal
4528
3/4
✓ Branch 0 taken 256639 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 256168 times.
✓ Branch 3 taken 471 times.
256639 if (is_ignorable_error(error)) return false;
4529
4530 // Catch errors that are not fatal
4531
2/3
✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 311 times.
471 switch (error) {
4532 /*
4533 Deadlock and lock timeout cause transaction/statement rollback so
4534 that THD::is_fatal_sub_stmt_error will be set. This means that they will
4535 not be possible to handle by stored program handlers inside stored
4536 functions and triggers even if non-fatal.
4537 */
4538 160 case HA_ERR_LOCK_WAIT_TIMEOUT:
4539 case HA_ERR_LOCK_DEADLOCK:
4540 160 return false;
4541
4542 case HA_ERR_NULL_IN_SPATIAL:
4543 return false;
4544 }
4545
4546 // Default is that an error is fatal
4547 311 return true;
4548 256639 }
4549
4550 /**
4551 Print error that we got from handler function.
4552
4553 @note
4554 In case of delete table it's only safe to use the following parts of
4555 the 'table' structure:
4556 - table->s->path
4557 - table->alias
4558 */
4559 258304 void handler::print_error(int error, myf errflag) {
4560
1/2
✓ Branch 0 taken 258305 times.
✗ Branch 1 not taken.
258304 THD *thd = current_thd;
4561 258305 Foreign_key_error_handler foreign_key_error_handler(thd, this);
4562
4563
1/2
✓ Branch 0 taken 258306 times.
✗ Branch 1 not taken.
258305 DBUG_TRACE;
4564
3/8
✓ Branch 0 taken 258306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 258306 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 258306 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
258306 DBUG_PRINT("enter", ("error: %d", error));
4565
4566 258305 int textno = ER_GET_ERRNO;
4567
40/60
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 54 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 255846 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 24 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 9 times.
✓ Branch 13 taken 14 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 11 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 11 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 39 times.
✓ Branch 20 taken 172 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 427 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 232 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 17 times.
✓ Branch 27 taken 90 times.
✓ Branch 28 taken 113 times.
✓ Branch 29 taken 13 times.
✓ Branch 30 taken 207 times.
✓ Branch 31 taken 8 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 13 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 39 times.
✓ Branch 36 taken 17 times.
✓ Branch 37 taken 25 times.
✓ Branch 38 taken 6 times.
✓ Branch 39 taken 12 times.
✓ Branch 40 taken 28 times.
✓ Branch 41 taken 12 times.
✓ Branch 42 taken 12 times.
✗ Branch 43 not taken.
✓ Branch 44 taken 169 times.
✗ Branch 45 not taken.
✓ Branch 46 taken 10 times.
✓ Branch 47 taken 5 times.
✗ Branch 48 not taken.
✓ Branch 49 taken 1 times.
✓ Branch 50 taken 54 times.
✓ Branch 51 taken 8 times.
✓ Branch 52 taken 20 times.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✓ Branch 55 taken 2 times.
✓ Branch 56 taken 3 times.
✓ Branch 57 taken 26 times.
✗ Branch 58 not taken.
✓ Branch 59 taken 533 times.
258305 switch (error) {
4568 case EACCES:
4569 textno = ER_OPEN_AS_READONLY;
4570 break;
4571 case EAGAIN:
4572 textno = ER_FILE_USED;
4573 break;
4574 17 case ENOENT: {
4575 char errbuf[MYSYS_STRERROR_SIZE];
4576 17 textno = ER_FILE_NOT_FOUND;
4577
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
17 my_error(textno, errflag, table_share->table_name.str, error,
4578 my_strerror(errbuf, sizeof(errbuf), error));
4579 17 } break;
4580 54 case HA_ERR_KEY_NOT_FOUND:
4581 case HA_ERR_NO_ACTIVE_RECORD:
4582 case HA_ERR_RECORD_DELETED:
4583 case HA_ERR_END_OF_FILE:
4584 54 textno = ER_KEY_NOT_FOUND;
4585 54 break;
4586 2 case HA_ERR_WRONG_MRG_TABLE_DEF:
4587 2 textno = ER_WRONG_MRG_TABLE;
4588 2 break;
4589 255846 case HA_ERR_FOUND_DUPP_KEY: {
4590
2/4
✓ Branch 0 taken 255846 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 255846 times.
✗ Branch 3 not taken.
255846 uint key_nr = table ? get_dup_key(error) : -1;
4591
2/2
✓ Branch 0 taken 255812 times.
✓ Branch 1 taken 34 times.
255846 if ((int)key_nr >= 0) {
4592
2/4
✓ Branch 0 taken 255812 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 255812 times.
✗ Branch 3 not taken.
511624 print_keydup_error(
4593 255812 table, key_nr == MAX_KEY ? nullptr : &table->key_info[key_nr],
4594 errflag);
4595 255812 return;
4596 }
4597 34 textno = ER_DUP_KEY;
4598 34 break;
4599 }
4600 4 case HA_ERR_FOREIGN_DUPLICATE_KEY: {
4601
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
4602
4603 char rec_buf[MAX_KEY_LENGTH];
4604 4 String rec(rec_buf, sizeof(rec_buf), system_charset_info);
4605 /* Table is opened and defined at this point */
4606
4607 /*
4608 Just print the subset of fields that are part of the first index,
4609 printing the whole row from there is not easy.
4610 */
4611
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 key_unpack(&rec, table, &table->key_info[0]);
4612
4613 char child_table_name[NAME_LEN + 1];
4614 char child_key_name[NAME_LEN + 1];
4615
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 if (get_foreign_dup_key(child_table_name, sizeof(child_table_name),
4616 child_key_name, sizeof(child_key_name))) {
4617
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 my_error(ER_FOREIGN_DUPLICATE_KEY_WITH_CHILD_INFO, errflag,
4618
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 table_share->table_name.str, rec.c_ptr_safe(),
4619 child_table_name, child_key_name);
4620 } else {
4621 my_error(ER_FOREIGN_DUPLICATE_KEY_WITHOUT_CHILD_INFO, errflag,
4622 table_share->table_name.str, rec.c_ptr_safe());
4623 }
4624 4 return;
4625 4 }
4626 case HA_ERR_NULL_IN_SPATIAL:
4627 my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, errflag);
4628 return;
4629 case HA_ERR_FOUND_DUPP_UNIQUE:
4630 textno = ER_DUP_UNIQUE;
4631 break;
4632 case HA_ERR_RECORD_CHANGED:
4633 textno = ER_CHECKREAD;
4634 break;
4635 24 case HA_ERR_CRASHED:
4636 24 textno = ER_NOT_KEYFILE;
4637 24 break;
4638 case HA_ERR_WRONG_IN_RECORD:
4639 textno = ER_CRASHED_ON_USAGE;
4640 break;
4641 9 case HA_ERR_CRASHED_ON_USAGE:
4642 9 textno = ER_CRASHED_ON_USAGE;
4643 9 break;
4644 14 case HA_ERR_NOT_A_TABLE:
4645 14 textno = error;
4646 14 break;
4647 case HA_ERR_CRASHED_ON_REPAIR:
4648 textno = ER_CRASHED_ON_REPAIR;
4649 break;
4650 11 case HA_ERR_OUT_OF_MEM:
4651 11 textno = ER_OUT_OF_RESOURCES;
4652 11 break;
4653 case HA_ERR_SE_OUT_OF_MEMORY:
4654 my_error(ER_ENGINE_OUT_OF_MEMORY, errflag, table->file->table_type());
4655 return;
4656 11 case HA_ERR_WRONG_COMMAND:
4657 11 textno = ER_ILLEGAL_HA;
4658 11 break;
4659 case HA_ERR_OLD_FILE:
4660 textno = ER_OLD_KEYFILE;
4661 break;
4662 39 case HA_ERR_UNSUPPORTED:
4663 39 textno = ER_UNSUPPORTED_EXTENSION;
4664 39 break;
4665 172 case HA_ERR_RECORD_FILE_FULL:
4666 case HA_ERR_INDEX_FILE_FULL: {
4667 172 textno = ER_RECORD_FILE_FULL;
4668 /* Write the error message to error log */
4669
8/16
✓ Branch 0 taken 172 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 172 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 172 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 172 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 172 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 172 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 172 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 172 times.
✗ Branch 15 not taken.
172 LogErr(ERROR_LEVEL, ER_SERVER_RECORD_FILE_FULL,
4670 table_share->table_name.str);
4671 172 break;
4672 }
4673 case HA_ERR_DISK_FULL_NOWAIT: {
4674 textno = ER_DISK_FULL_NOWAIT;
4675 /* Write the error message to error log */
4676 LogErr(ERROR_LEVEL, ER_SERVER_DISK_FULL_NOWAIT,
4677 table_share->table_name.str);
4678 break;
4679 }
4680 427 case HA_ERR_LOCK_WAIT_TIMEOUT:
4681 427 textno = ER_LOCK_WAIT_TIMEOUT;
4682 427 break;
4683 case HA_ERR_LOCK_TABLE_FULL:
4684 textno = ER_LOCK_TABLE_FULL;
4685 break;
4686 232 case HA_ERR_LOCK_DEADLOCK:
4687 232 textno = ER_LOCK_DEADLOCK;
4688 232 break;
4689 case HA_ERR_READ_ONLY_TRANSACTION:
4690 textno = ER_READ_ONLY_TRANSACTION;
4691 break;
4692 17 case HA_ERR_CANNOT_ADD_FOREIGN:
4693 17 textno = ER_CANNOT_ADD_FOREIGN;
4694 17 break;
4695 90 case HA_ERR_ROW_IS_REFERENCED: {
4696 90 String str;
4697 /*
4698 Manipulate the error message while handling the error
4699 condition based on the access check.
4700 */
4701
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 thd->push_internal_handler(&foreign_key_error_handler);
4702
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 get_error_message(error, &str);
4703
2/4
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
90 my_error(ER_ROW_IS_REFERENCED_2, errflag, str.c_ptr_safe());
4704
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 thd->pop_internal_handler();
4705 90 return;
4706 90 }
4707 113 case HA_ERR_NO_REFERENCED_ROW: {
4708 113 String str;
4709 /*
4710 Manipulate the error message while handling the error
4711 condition based on the access check.
4712 */
4713
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 thd->push_internal_handler(&foreign_key_error_handler);
4714
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 get_error_message(error, &str);
4715
2/4
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 113 times.
✗ Branch 3 not taken.
113 my_error(ER_NO_REFERENCED_ROW_2, errflag, str.c_ptr_safe());
4716
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 thd->pop_internal_handler();
4717 113 return;
4718 113 }
4719 13 case HA_ERR_TABLE_DEF_CHANGED:
4720 13 textno = ER_TABLE_DEF_CHANGED;
4721 13 break;
4722 207 case HA_ERR_NO_SUCH_TABLE:
4723 207 my_error(ER_NO_SUCH_TABLE, errflag, table_share->db.str,
4724
1/2
✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
207 table_share->table_name.str);
4725 207 return;
4726 8 case HA_ERR_RBR_LOGGING_FAILED:
4727 8 textno = ER_BINLOG_ROW_LOGGING_FAILED;
4728 8 break;
4729 case HA_ERR_DROP_INDEX_FK: {
4730 const char *ptr = "???";
4731 uint key_nr = table ? get_dup_key(error) : -1;
4732 if ((int)key_nr >= 0 && key_nr != MAX_KEY)
4733 ptr = table->key_info[key_nr].name;
4734 my_error(ER_DROP_INDEX_FK, errflag, ptr);
4735 return;
4736 }
4737 13 case HA_ERR_TABLE_NEEDS_UPGRADE:
4738 13 textno = ER_TABLE_NEEDS_UPGRADE;
4739 13 break;
4740 case HA_ERR_NO_PARTITION_FOUND:
4741 textno = ER_WRONG_PARTITION_NAME;
4742 break;
4743 39 case HA_ERR_TABLE_READONLY:
4744 39 textno = ER_OPEN_AS_READONLY;
4745 39 break;
4746 17 case HA_ERR_AUTOINC_READ_FAILED:
4747 17 textno = ER_AUTOINC_READ_FAILED;
4748 17 break;
4749 25 case HA_ERR_AUTOINC_ERANGE:
4750 25 textno = ER_WARN_DATA_OUT_OF_RANGE;
4751 25 break;
4752 6 case HA_ERR_TOO_MANY_CONCURRENT_TRXS:
4753 6 textno = ER_TOO_MANY_CONCURRENT_TRXS;
4754 6 break;
4755 12 case HA_ERR_INDEX_COL_TOO_LONG:
4756 12 textno = ER_INDEX_COLUMN_TOO_LONG;
4757 12 break;
4758 28 case HA_ERR_NOT_IN_LOCK_PARTITIONS:
4759 28 textno = ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET;
4760 28 break;
4761 12 case HA_ERR_INDEX_CORRUPT:
4762 12 textno = ER_INDEX_CORRUPT;
4763 12 break;
4764 12 case HA_ERR_UNDO_REC_TOO_BIG:
4765 12 textno = ER_UNDO_RECORD_TOO_BIG;
4766 12 break;
4767 case HA_ERR_TABLE_IN_FK_CHECK:
4768 textno = ER_TABLE_IN_FK_CHECK;
4769 break;
4770 169 case HA_WRONG_CREATE_OPTION:
4771 169 textno = ER_ILLEGAL_HA;
4772 169 break;
4773 case HA_MISSING_CREATE_OPTION: {
4774 const char *engine = table_type();
4775 my_error(ER_MISSING_HA_CREATE_OPTION, errflag, engine);
4776 return;
4777 }
4778 10 case HA_ERR_TOO_MANY_FIELDS:
4779 10 textno = ER_TOO_MANY_FIELDS;
4780 10 break;
4781 5 case HA_ERR_INNODB_READ_ONLY:
4782 5 textno = ER_INNODB_READ_ONLY;
4783 5 break;
4784 case HA_ERR_TEMP_FILE_WRITE_FAILURE:
4785 textno = ER_TEMP_FILE_WRITE_FAILURE;
4786 break;
4787 1 case HA_ERR_INNODB_FORCED_RECOVERY:
4788 1 textno = ER_INNODB_FORCED_RECOVERY;
4789 1 break;
4790 54 case HA_ERR_TABLE_CORRUPT:
4791 54 my_error(ER_TABLE_CORRUPT, errflag, table_share->db.str,
4792
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 table_share->table_name.str);
4793 54 return;
4794 8 case HA_ERR_QUERY_INTERRUPTED:
4795 8 textno = ER_QUERY_INTERRUPTED;
4796 8 break;
4797 20 case HA_ERR_TABLESPACE_MISSING: {
4798 char errbuf[MYSYS_STRERROR_SIZE];
4799 20 snprintf(errbuf, MYSYS_STRERROR_SIZE, "`%s`.`%s`", table_share->db.str,
4800 20 table_share->table_name.str);
4801
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 my_error(ER_TABLESPACE_MISSING, errflag, errbuf, error);
4802 20 return;
4803 }
4804 case HA_ERR_TABLESPACE_IS_NOT_EMPTY:
4805 my_error(ER_TABLESPACE_IS_NOT_EMPTY, errflag, table_share->db.str,
4806 table_share->table_name.str);
4807 return;
4808 case HA_ERR_WRONG_FILE_NAME:
4809 my_error(ER_WRONG_FILE_NAME, errflag, table_share->table_name.str);
4810 return;
4811 2 case HA_ERR_NOT_ALLOWED_COMMAND:
4812 2 textno = ER_NOT_ALLOWED_COMMAND;
4813 2 break;
4814 3 case HA_ERR_NO_SESSION_TEMP:
4815 3 textno = ER_NO_SESSION_TEMP;
4816 3 break;
4817 26 case HA_ERR_WRONG_TABLE_NAME:
4818 26 textno = ER_WRONG_TABLE_NAME;
4819 26 break;
4820 case HA_ERR_TOO_LONG_PATH:
4821 textno = ER_TABLE_NAME_CAUSES_TOO_LONG_PATH;
4822 break;
4823 533 default: {
4824 /* The error was "unknown" to this function.
4825 Ask handler if it has got a message for this error */
4826 533 String str;
4827
1/2
✓ Branch 0 taken 533 times.
✗ Branch 1 not taken.
533 bool temporary = get_error_message(error, &str);
4828
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 528 times.
533 if (!str.is_empty()) {
4829
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 const char *engine = table_type();
4830
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (temporary)
4831 my_error(ER_GET_TEMPORARY_ERRMSG, errflag, error, str.ptr(), engine);
4832 else
4833
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 my_error(ER_GET_ERRMSG, errflag, error, str.ptr(), engine);
4834 } else {
4835 char errbuf[MYSQL_ERRMSG_SIZE];
4836
2/4
✓ Branch 0 taken 528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 528 times.
✗ Branch 3 not taken.
528 my_error(ER_GET_ERRNO, errflag, error,
4837 my_strerror(errbuf, MYSQL_ERRMSG_SIZE, error));
4838 }
4839 533 return;
4840 533 }
4841 }
4842
2/2
✓ Branch 0 taken 1455 times.
✓ Branch 1 taken 17 times.
1472 if (textno != ER_FILE_NOT_FOUND)
4843
1/2
✓ Branch 0 taken 1456 times.
✗ Branch 1 not taken.
1455 my_error(textno, errflag, table_share->table_name.str, error);
4844
4/4
✓ Branch 0 taken 1472 times.
✓ Branch 1 taken 256833 times.
✓ Branch 2 taken 1472 times.
✓ Branch 3 taken 256833 times.
515139 }
4845
4846 /**
4847 Return an error message specific to this handler.
4848
4849 @param error error code previously returned by handler
4850 @param buf pointer to String where to add error message
4851
4852 @return
4853 Returns true if this is a temporary error
4854 */
4855 185 bool handler::get_error_message(int error [[maybe_unused]],
4856 String *buf [[maybe_unused]]) {
4857 185 return false;
4858 }
4859
4860 /**
4861 Check for incompatible collation changes.
4862
4863 @retval
4864 HA_ADMIN_NEEDS_UPGRADE Table may have data requiring upgrade.
4865 @retval
4866 0 No upgrade required.
4867 */
4868
4869 1034 int handler::check_collation_compatibility() {
4870 1034 ulong mysql_version = table->s->mysql_version;
4871
4872
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1034 times.
1034 if (mysql_version < 50124) {
4873 KEY *key = table->key_info;
4874 KEY *key_end = key + table->s->keys;
4875 for (; key < key_end; key++) {
4876 KEY_PART_INFO *key_part = key->key_part;
4877 KEY_PART_INFO *key_part_end = key_part + key->user_defined_key_parts;
4878 for (; key_part < key_part_end; key_part++) {
4879 if (!key_part->fieldnr) continue;
4880 Field *field = table->field[key_part->fieldnr - 1];
4881 uint cs_number = field->charset()->number;
4882 if ((mysql_version < 50048 &&
4883 (cs_number == 11 || /* ascii_general_ci - bug #29499, bug #27562 */
4884 cs_number == 41 || /* latin7_general_ci - bug #29461 */
4885 cs_number == 42 || /* latin7_general_cs - bug #29461 */
4886 cs_number == 20 || /* latin7_estonian_cs - bug #29461 */
4887 cs_number == 21 || /* latin2_hungarian_ci - bug #29461 */
4888 cs_number == 22 || /* koi8u_general_ci - bug #29461 */
4889 cs_number == 23 || /* cp1251_ukrainian_ci - bug #29461 */
4890 cs_number == 26)) || /* cp1250_general_ci - bug #29461 */
4891 (mysql_version < 50124 &&
4892 (cs_number == 33 || /* utf8mb3_general_ci - bug #27877 */
4893 cs_number == 35))) /* ucs2_general_ci - bug #27877 */
4894 return HA_ADMIN_NEEDS_UPGRADE;
4895 }
4896 }
4897 }
4898 1034 return 0;
4899 }
4900
4901 1034 int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) {
4902 int error;
4903 KEY *keyinfo, *keyend;
4904 KEY_PART_INFO *keypart, *keypartend;
4905
4906
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1034 times.
1034 if (!table->s->mysql_version) {
4907 /* check for blob-in-key error */
4908 keyinfo = table->key_info;
4909 keyend = table->key_info + table->s->keys;
4910 for (; keyinfo < keyend; keyinfo++) {
4911 keypart = keyinfo->key_part;
4912 keypartend = keypart + keyinfo->user_defined_key_parts;
4913 for (; keypart < keypartend; keypart++) {
4914 if (!keypart->fieldnr) continue;
4915 Field *field = table->field[keypart->fieldnr - 1];
4916 if (field->type() == MYSQL_TYPE_BLOB) {
4917 if (check_opt->sql_flags & TT_FOR_UPGRADE)
4918 check_opt->flags = T_MEDIUM;
4919 return HA_ADMIN_NEEDS_CHECK;
4920 }
4921 }
4922 }
4923 }
4924
4925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1034 times.
1034 if ((error = check_collation_compatibility())) return error;
4926
4927 1034 return check_for_upgrade(check_opt);
4928 }
4929
4930 // Function identifies any old data type present in table.
4931 6087 int check_table_for_old_types(const TABLE *table, bool check_temporal_upgrade) {
4932 Field **field;
4933
4934
2/2
✓ Branch 0 taken 30715 times.
✓ Branch 1 taken 6083 times.
36798 for (field = table->field; (*field); field++) {
4935
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30715 times.
30715 if (table->s->mysql_version == 0) // prior to MySQL 5.0
4936 {
4937 /* check for bad DECIMAL field */
4938 if ((*field)->type() == MYSQL_TYPE_NEWDECIMAL) {
4939 return HA_ADMIN_NEEDS_ALTER;
4940 }
4941 if ((*field)->type() == MYSQL_TYPE_VAR_STRING) {
4942 return HA_ADMIN_NEEDS_ALTER;
4943 }
4944 }
4945
4946 /*
4947 Check for old DECIMAL field.
4948
4949 Above check does not take into account for pre 5.0 decimal types which can
4950 be present in the data directory if user did in-place upgrade from
4951 mysql-4.1 to mysql-5.0.
4952 */
4953
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 30713 times.
30715 if ((*field)->type() == MYSQL_TYPE_DECIMAL) {
4954 2 return HA_ADMIN_NEEDS_DUMP_UPGRADE;
4955 }
4956
4957
4/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 30704 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 30713 times.
30713 if ((*field)->type() == MYSQL_TYPE_YEAR && (*field)->field_length == 2)
4958 return HA_ADMIN_NEEDS_ALTER; // obsolete YEAR(2) type
4959
4960
1/2
✓ Branch 0 taken 30713 times.
✗ Branch 1 not taken.
30713 if (check_temporal_upgrade) {
4961 30713 if (((*field)->real_type() == MYSQL_TYPE_TIME) ||
4962
5/6
✓ Branch 0 taken 30711 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 30711 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 30711 times.
61424 ((*field)->real_type() == MYSQL_TYPE_DATETIME) ||
4963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30711 times.
30711 ((*field)->real_type() == MYSQL_TYPE_TIMESTAMP))
4964 2 return HA_ADMIN_NEEDS_ALTER;
4965 }
4966 }
4967 6083 return 0;
4968 }
4969
4970 /**
4971 @return
4972 key if error because of duplicated keys
4973 */
4974 928022 uint handler::get_dup_key(int error) {
4975
3/4
✓ Branch 0 taken 926756 times.
✓ Branch 1 taken 1266 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 926756 times.
928022 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
4976
1/2
✓ Branch 0 taken 928022 times.
✗ Branch 1 not taken.
928022 DBUG_TRACE;
4977 928022 table->file->errkey = (uint)-1;
4978
4/6
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 928015 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
928022 if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOUND_DUPP_UNIQUE ||
4979
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 error == HA_ERR_NULL_IN_SPATIAL || error == HA_ERR_DROP_INDEX_FK)
4980
1/2
✓ Branch 0 taken 928015 times.
✗ Branch 1 not taken.
928015 table->file->info(HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK);
4981 928022 return table->file->errkey;
4982 928022 }
4983
4984 bool handler::get_foreign_dup_key(char *, uint, char *, uint) {
4985 assert(false);
4986 return (false);
4987 }
4988
4989 2966 int handler::delete_table(const char *name, const dd::Table *) {
4990 2966 int saved_error = 0;
4991 2966 int error = 0;
4992 2966 int enoent_or_zero = ENOENT; // Error if no file was deleted
4993 char buff[FN_REFLEN];
4994 const char **start_ext;
4995
4996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2966 times.
2966 assert(m_lock_type == F_UNLCK);
4997
4998
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 2847 times.
2966 if (!(start_ext = ht->file_extensions)) return 0;
4999
2/2
✓ Branch 0 taken 4319 times.
✓ Branch 1 taken 2847 times.
7166 for (const char **ext = start_ext; *ext; ext++) {
5000
1/2
✓ Branch 0 taken 4319 times.
✗ Branch 1 not taken.
4319 fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME | MY_APPEND_EXT);
5001
3/4
✓ Branch 0 taken 4319 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 4316 times.
4319 if (mysql_file_delete_with_symlink(key_file_misc, buff, MYF(0))) {
5002
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (my_errno() != ENOENT) {
5003 /*
5004 If error on the first existing file, return the error.
5005 Otherwise delete as much as possible.
5006 */
5007 if (enoent_or_zero) return my_errno();
5008 saved_error = my_errno();
5009 }
5010 } else
5011 4316 enoent_or_zero = 0; // No error for ENOENT
5012 4319 error = enoent_or_zero;
5013 }
5014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2847 times.
2847 return saved_error ? saved_error : error;
5015 }
5016
5017 1235 int handler::rename_table(const char *from, const char *to,
5018 const dd::Table *from_table_def [[maybe_unused]],
5019 dd::Table *to_table_def [[maybe_unused]]) {
5020 1235 int error = 0;
5021 const char **ext, **start_ext;
5022
5023
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 1193 times.
1235 if (!(start_ext = ht->file_extensions)) return 0;
5024
2/2
✓ Branch 0 taken 2357 times.
✓ Branch 1 taken 1193 times.
3550 for (ext = start_ext; *ext; ext++) {
5025
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2357 times.
2357 if (rename_file_ext(from, to, *ext)) {
5026 error = my_errno();
5027 if (error != ENOENT) break;
5028 error = 0;
5029 }
5030 }
5031
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1193 times.
1193 if (error) {
5032 /* Try to revert the rename. Ignore errors. */
5033 for (; ext >= start_ext; ext--) rename_file_ext(to, from, *ext);
5034 }
5035 1193 return error;
5036 }
5037
5038 483017 void handler::drop_table(const char *name) {
5039 483017 close();
5040 483017 delete_table(name, nullptr);
5041 483016 }
5042
5043 /**
5044 Performs checks upon the table.
5045
5046 @param thd thread doing CHECK TABLE operation
5047 @param check_opt options from the parser
5048
5049 @retval
5050 HA_ADMIN_OK Successful upgrade
5051 @retval
5052 HA_ADMIN_NEEDS_UPGRADE Table has structures requiring upgrade
5053 @retval
5054 HA_ADMIN_NEEDS_ALTER Table has structures requiring ALTER TABLE
5055 @retval
5056 HA_ADMIN_NOT_IMPLEMENTED
5057 */
5058 11031 int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) {
5059 int error;
5060
3/4
✓ Branch 0 taken 11021 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11021 times.
11031 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
5061
5062
2/2
✓ Branch 0 taken 10860 times.
✓ Branch 1 taken 171 times.
11031 if ((table->s->mysql_version >= MYSQL_VERSION_ID) &&
5063
2/2
✓ Branch 0 taken 8370 times.
✓ Branch 1 taken 2490 times.
10860 (check_opt->sql_flags & TT_FOR_UPGRADE))
5064 8370 return 0;
5065
5066
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 2490 times.
2661 if (table->s->mysql_version < MYSQL_VERSION_ID) {
5067 // Check for old temporal format if avoid_temporal_upgrade is disabled.
5068 171 mysql_mutex_lock(&LOCK_global_system_variables);
5069 171 const bool check_temporal_upgrade = !avoid_temporal_upgrade;
5070 171 mysql_mutex_unlock(&LOCK_global_system_variables);
5071
5072
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
171 if ((error = check_table_for_old_types(table, check_temporal_upgrade)))
5073 return error;
5074 171 error = ha_check_for_upgrade(check_opt);
5075
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
171 if (error && (error != HA_ADMIN_NEEDS_CHECK)) return error;
5076
3/4
✓ Branch 0 taken 171 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 128 times.
✓ Branch 3 taken 43 times.
171 if (!error && (check_opt->sql_flags & TT_FOR_UPGRADE)) return 0;
5077 }
5078 2533 return check(thd, check_opt);
5079 }
5080
5081 /**
5082 A helper function to mark a transaction read-write,
5083 if it is started.
5084 */
5085
5086 176907964 void handler::mark_trx_read_write() {
5087 176907964 Ha_trx_info *ha_info = &ha_thd()->get_ha_data(ht->slot)->ha_info[0];
5088 /*
5089 When a storage engine method is called, the transaction must
5090 have been started, unless it's a DDL call, for which the
5091 storage engine starts the transaction internally, and commits
5092 it internally, without registering in the ha_list.
5093 Unfortunately here we can't know for sure if the engine
5094 has registered the transaction or not, so we must check.
5095 */
5096
2/2
✓ Branch 0 taken 98116045 times.
✓ Branch 1 taken 78792842 times.
176909154 if (ha_info->is_started()) {
5097
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98116045 times.
98116045 assert(has_transactions());
5098 /*
5099 table_share can be NULL in ha_delete_table(). See implementation
5100 of standalone function ha_delete_table() in sql_base.cc.
5101 */
5102
4/4
✓ Branch 0 taken 98053646 times.
✓ Branch 1 taken 62399 times.
✓ Branch 2 taken 77673354 times.
✓ Branch 3 taken 20380292 times.
98116045 if (table_share == nullptr || table_share->tmp_table == NO_TMP_TABLE) {
5103 /* TempTable and Heap tables don't use/support transactions. */
5104 77735753 ha_info->set_trx_read_write();
5105 }
5106 }
5107 176908951 }
5108
5109 /**
5110 Repair table: public interface.
5111
5112 @sa handler::repair()
5113 */
5114
5115 877 int handler::ha_repair(THD *thd, HA_CHECK_OPT *check_opt) {
5116 int result;
5117 877 mark_trx_read_write();
5118
5119 877 result = repair(thd, check_opt);
5120
3/4
✓ Branch 0 taken 769 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 769 times.
877 assert(result == HA_ADMIN_NOT_IMPLEMENTED ||
5121 ha_table_flags() & HA_CAN_REPAIR);
5122
5123 // TODO: Check if table version in DD needs to be updated.
5124 // Previously we checked/updated FRM version here.
5125 877 return result;
5126 }
5127
5128 /**
5129 Start bulk insert.
5130
5131 Allow the handler to optimize for multiple row insert.
5132
5133 @note rows == 0 means we will probably insert many rows.
5134
5135 @param rows Estimated rows to insert
5136 */
5137
5138 6254817 void handler::ha_start_bulk_insert(ha_rows rows) {
5139
1/2
✓ Branch 0 taken 6256200 times.
✗ Branch 1 not taken.
6254817 DBUG_TRACE;
5140
3/4
✓ Branch 0 taken 6103918 times.
✓ Branch 1 taken 152282 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6103918 times.
6256200 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
5141 6256200 estimation_rows_to_insert = rows;
5142
1/2
✓ Branch 0 taken 6255322 times.
✗ Branch 1 not taken.
6256200 start_bulk_insert(rows);
5143 6255322 }
5144
5145 /**
5146 End bulk insert.
5147
5148 @return Operation status
5149 @retval 0 Success
5150 @retval != 0 Failure (error code returned)
5151 */
5152
5153 6255915 int handler::ha_end_bulk_insert() {
5154
1/2
✓ Branch 0 taken 6256349 times.
✗ Branch 1 not taken.
6255915 DBUG_TRACE;
5155
3/4
✓ Branch 0 taken 6104073 times.
✓ Branch 1 taken 152276 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6104073 times.
6256349 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
5156 6256349 estimation_rows_to_insert = 0;
5157
1/2
✓ Branch 0 taken 6256217 times.
✗ Branch 1 not taken.
12512748 return end_bulk_insert();
5158 6256217 }
5159
5160 /**
5161 Bulk update row: public interface.
5162
5163 @sa handler::bulk_update_row()
5164 */
5165
5166 int handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data,
5167 uint *dup_key_found) {
5168 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
5169 mark_trx_read_write();
5170
5171 return bulk_update_row(old_data, new_data, dup_key_found);
5172 }
5173
5174 /**
5175 Delete all rows: public interface.
5176
5177 @sa handler::delete_all_rows()
5178 */
5179
5180 397011 int handler::ha_delete_all_rows() {
5181
3/4
✓ Branch 0 taken 3076 times.
✓ Branch 1 taken 393935 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3076 times.
397011 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
5182 397011 mark_trx_read_write();
5183
5184 397011 return delete_all_rows();
5185 }
5186
5187 /**
5188 Truncate table: public interface.
5189
5190 @sa handler::truncate()
5191 */
5192
5193 6008 int handler::ha_truncate(dd::Table *table_def) {
5194
2/4
✓ Branch 0 taken 6008 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6008 times.
6008 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
5195 6008 mark_trx_read_write();
5196
5197 6008 return truncate(table_def);
5198 }
5199
5200 /**
5201 Optimize table: public interface.
5202
5203 @sa handler::optimize()
5204 */
5205
5206 2829 int handler::ha_optimize(THD *thd, HA_CHECK_OPT *check_opt) {
5207
3/4
✓ Branch 0 taken 2818 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2818 times.
2829 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
5208 2829 mark_trx_read_write();
5209
5210 2829 return optimize(thd, check_opt);
5211 }
5212
5213 /**
5214 Analyze table: public interface.
5215
5216 @sa handler::analyze()
5217 */
5218
5219 14406 int handler::ha_analyze(THD *thd, HA_CHECK_OPT *check_opt) {
5220
3/4
✓ Branch 0 taken 14388 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14388 times.
14406 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
5221 14406 mark_trx_read_write();
5222
5223 14406 return analyze(thd, check_opt);
5224 }
5225
5226 /**
5227 Check and repair table: public interface.
5228
5229 @sa handler::check_and_repair()
5230 */
5231
5232 4 bool handler::ha_check_and_repair(THD *thd) {
5233
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_UNLCK);
5234 4 mark_trx_read_write();
5235
5236 4 return check_and_repair(thd);
5237 }
5238
5239 /**
5240 Disable indexes: public interface.
5241
5242 @sa handler::disable_indexes()
5243 */
5244
5245 727 int handler::ha_disable_indexes(uint mode) {
5246
3/4
✓ Branch 0 taken 691 times.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 691 times.
727 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
5247 727 mark_trx_read_write();
5248
5249 727 return disable_indexes(mode);
5250 }
5251
5252 /**
5253 Enable indexes: public interface.
5254
5255 @sa handler::enable_indexes()
5256 */
5257
5258 701 int handler::ha_enable_indexes(uint mode) {
5259
3/4
✓ Branch 0 taken 685 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 685 times.
701 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
5260 701 mark_trx_read_write();
5261
5262 701 return enable_indexes(mode);
5263 }
5264
5265 /**
5266 Discard or import tablespace: public interface.
5267
5268 @sa handler::discard_or_import_tablespace()
5269 */
5270
5271 932 int handler::ha_discard_or_import_tablespace(bool discard,
5272 dd::Table *table_def) {
5273
3/4
✓ Branch 0 taken 916 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 916 times.
932 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
5274 932 mark_trx_read_write();
5275
5276 932 return discard_or_import_tablespace(discard, table_def);
5277 }
5278
5279 67979 bool handler::ha_prepare_inplace_alter_table(TABLE *altered_table,
5280 Alter_inplace_info *ha_alter_info,
5281 const dd::Table *old_table_def,
5282 dd::Table *new_table_def) {
5283
3/4
✓ Branch 0 taken 67949 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67949 times.
67979 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type != F_UNLCK);
5284 67979 mark_trx_read_write();
5285
5286 67979 return prepare_inplace_alter_table(altered_table, ha_alter_info,
5287 67810 old_table_def, new_table_def);
5288 }
5289
5290 67821 bool handler::ha_commit_inplace_alter_table(TABLE *altered_table,
5291 Alter_inplace_info *ha_alter_info,
5292 bool commit,
5293 const dd::Table *old_table_def,
5294 dd::Table *new_table_def) {
5295 /*
5296 At this point we should have an exclusive metadata lock on the table.
5297 The exception is if we're about to roll back changes (commit= false).
5298 In this case, we might be rolling back after a failed lock upgrade,
5299 so we could be holding the same lock level as for inplace_alter_table().
5300 TABLE::mdl_ticket is 0 for temporary tables.
5301 */
5302
6/8
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 67792 times.
✓ Branch 2 taken 29 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 562 times.
✓ Branch 5 taken 67230 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 562 times.
67821 assert((table->s->tmp_table != NO_TMP_TABLE && !table->mdl_ticket) ||
5303 (ha_thd()->mdl_context.owns_equal_or_stronger_lock(
5304 MDL_key::TABLE, table->s->db.str, table->s->table_name.str,
5305 MDL_EXCLUSIVE) ||
5306 !commit));
5307
5308 67821 return commit_inplace_alter_table(altered_table, ha_alter_info, commit,
5309 67702 old_table_def, new_table_def);
5310 }
5311
5312 /*
5313 Default implementation to support in-place/instant alter table
5314 for operations which do not affect table data.
5315 */
5316
5317 13965 enum_alter_inplace_result handler::check_if_supported_inplace_alter(
5318 TABLE *altered_table [[maybe_unused]], Alter_inplace_info *ha_alter_info) {
5319
1/2
✓ Branch 0 taken 13965 times.
✗ Branch 1 not taken.
13965 DBUG_TRACE;
5320
5321 13965 HA_CREATE_INFO *create_info = ha_alter_info->create_info;
5322
5323 13965 Alter_inplace_info::HA_ALTER_FLAGS inplace_offline_operations =
5324 Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH |
5325 Alter_inplace_info::ALTER_COLUMN_NAME |
5326 Alter_inplace_info::ALTER_COLUMN_DEFAULT |
5327 Alter_inplace_info::CHANGE_CREATE_OPTION |
5328 Alter_inplace_info::ALTER_RENAME | Alter_inplace_info::RENAME_INDEX |
5329 Alter_inplace_info::ALTER_INDEX_COMMENT |
5330 Alter_inplace_info::CHANGE_INDEX_OPTION |
5331 Alter_inplace_info::ALTER_COLUMN_INDEX_LENGTH;
5332
5333 /* Is there at least one operation that requires copy algorithm? */
5334
2/2
✓ Branch 0 taken 10953 times.
✓ Branch 1 taken 3012 times.
13965 if (ha_alter_info->handler_flags & ~inplace_offline_operations)
5335 10953 return HA_ALTER_INPLACE_NOT_SUPPORTED;
5336
5337 /*
5338 ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. and
5339 ALTER TABLE table_name DEFAULT CHARSET = .. most likely
5340 change column charsets and so not supported in-place through
5341 old API.
5342
5343 Changing of PACK_KEYS, MAX_ROWS and ROW_FORMAT options were
5344 not supported as in-place operations in old API either.
5345 */
5346
2/2
✓ Branch 0 taken 2689 times.
✓ Branch 1 taken 323 times.
3012 if (create_info->used_fields &
5347 (HA_CREATE_USED_CHARSET | HA_CREATE_USED_DEFAULT_CHARSET |
5348 2689 HA_CREATE_USED_PACK_KEYS | HA_CREATE_USED_MAX_ROWS) ||
5349
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2628 times.
2689 (table->s->row_type != create_info->row_type))
5350 384 return HA_ALTER_INPLACE_NOT_SUPPORTED;
5351
5352 // The presence of engine attributes does not prevent inplace so
5353 // that we get the same behavior as COMMENT. If SEs support engine
5354 // attribute values which are incompatible with INPLACE the need to
5355 // check for that when overriding (as they must do for parsed
5356 // comments).
5357
5358 5256 uint table_changes = (ha_alter_info->handler_flags &
5359 Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH)
5360
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 2605 times.
2628 ? IS_EQUAL_PACK_LENGTH
5361 : IS_EQUAL_YES;
5362
3/4
✓ Branch 0 taken 2628 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2585 times.
✓ Branch 3 taken 43 times.
2628 if (table->file->check_if_incompatible_data(create_info, table_changes) ==
5363 COMPATIBLE_DATA_YES)
5364 2585 return HA_ALTER_INPLACE_INSTANT;
5365
5366 43 return HA_ALTER_INPLACE_NOT_SUPPORTED;
5367 13965 }
5368
5369 251 void Alter_inplace_info::report_unsupported_error(const char *not_supported,
5370 const char *try_instead) {
5371
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 153 times.
251 if (unsupported_reason == nullptr)
5372 98 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), not_supported,
5373 try_instead);
5374 else
5375 153 my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), not_supported,
5376 unsupported_reason, try_instead);
5377 251 }
5378
5379 /**
5380 Rename table: public interface.
5381
5382 @sa handler::rename_table()
5383 */
5384
5385 40356 int handler::ha_rename_table(const char *from, const char *to,
5386 const dd::Table *from_table_def,
5387 dd::Table *to_table_def) {
5388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40356 times.
40356 assert(m_lock_type == F_UNLCK);
5389 40356 mark_trx_read_write();
5390
5391 40356 return rename_table(from, to, from_table_def, to_table_def);
5392 }
5393
5394 /**
5395 Delete table: public interface.
5396
5397 @sa handler::delete_table()
5398 */
5399
5400 218314 int handler::ha_delete_table(const char *name, const dd::Table *table_def) {
5401
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218314 times.
218314 assert(m_lock_type == F_UNLCK);
5402 218314 mark_trx_read_write();
5403
5404 218315 return delete_table(name, table_def);
5405 }
5406
5407 /**
5408 Drop table in the engine: public interface.
5409
5410 @sa handler::drop_table()
5411 */
5412
5413 599430 void handler::ha_drop_table(const char *name) {
5414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 599430 times.
599430 assert(m_lock_type == F_UNLCK);
5415 599430 mark_trx_read_write();
5416
5417 599430 return drop_table(name);
5418 }
5419
5420 /**
5421 Create a table in the engine: public interface.
5422
5423 @sa handler::create()
5424 */
5425
5426 329629 int handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info,
5427 dd::Table *table_def) {
5428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 329629 times.
329629 assert(m_lock_type == F_UNLCK);
5429 329629 mark_trx_read_write();
5430
5431 329629 return create(name, form, info, table_def);
5432 }
5433
5434 /**
5435 * Loads a table into its defined secondary storage engine: public interface.
5436 * This call may downgrade the table lock. Do not make any assumptions on the
5437 * MDL.
5438 *
5439 * @param table The table to load into the secondary engine. Its read_set tells
5440 * which columns to load.
5441 *
5442 * @sa handler::load_table()
5443 */
5444 87 int handler::ha_load_table(const TABLE &table) { return load_table(table); }
5445
5446 /**
5447 * Unloads a table from its defined secondary storage engine: public interface.
5448 *
5449 * @sa handler::unload_table()
5450 */
5451 112 int handler::ha_unload_table(const char *db_name, const char *table_name,
5452 bool error_if_not_loaded) {
5453 112 return unload_table(db_name, table_name, error_if_not_loaded);
5454 }
5455
5456 /**
5457 Get the hard coded SE private data from the handler for a DD table.
5458
5459 @sa handler::get_se_private_data()
5460 */
5461 19008 bool handler::ha_get_se_private_data(dd::Table *dd_table, bool reset) {
5462 19008 return get_se_private_data(dd_table, reset);
5463 }
5464
5465 /**
5466 Tell the storage engine that it is allowed to "disable transaction" in the
5467 handler. It is a hint that ACID is not required - it is used in NDB for
5468 ALTER TABLE, for example, when data are copied to temporary table.
5469 A storage engine may treat this hint any way it likes. NDB for example
5470 starts to commit every now and then automatically.
5471 This hint can be safely ignored.
5472 */
5473 25437 int ha_enable_transaction(THD *thd, bool on) {
5474 25437 int error = 0;
5475
1/2
✓ Branch 0 taken 25440 times.
✗ Branch 1 not taken.
25437 DBUG_TRACE;
5476
3/8
✓ Branch 0 taken 25436 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25440 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25440 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
25440 DBUG_PRINT("enter", ("on: %d", (int)on));
5477
5478 #ifdef WITH_WSREP
5479
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 25263 times.
25439 if (thd->wsrep_applier) return 0;
5480 #endif /* WITH_WSREP */
5481
5482
2/2
✓ Branch 0 taken 12629 times.
✓ Branch 1 taken 12635 times.
25263 if ((thd->get_transaction()->m_flags.enabled = on)) {
5483 /*
5484 Now all storage engines should have transaction handling enabled.
5485 But some may have it enabled all the time - "disabling" transactions
5486 is an optimization hint that storage engine is free to ignore.
5487 So, let's commit an open transaction (if any) now.
5488 */
5489
2/4
✓ Branch 0 taken 12628 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12628 times.
✗ Branch 3 not taken.
12629 if (!(error = ha_commit_trans(thd, false)))
5490
1/2
✓ Branch 0 taken 12627 times.
✗ Branch 1 not taken.
12628 error = trans_commit_implicit(thd);
5491 }
5492 25262 return error;
5493 25438 }
5494
5495 488 int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) {
5496 int error;
5497
1/2
✓ Branch 0 taken 488 times.
✗ Branch 1 not taken.
488 DBUG_TRACE;
5498
3/4
✓ Branch 0 taken 488 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 349 times.
✓ Branch 3 taken 139 times.
488 if (!(error = index_next(buf))) {
5499 349 ptrdiff_t ptrdiff = buf - table->record[0];
5500 349 uchar *save_record_0 = nullptr;
5501 349 KEY *key_info = nullptr;
5502 349 KEY_PART_INFO *key_part = nullptr;
5503 349 KEY_PART_INFO *key_part_end = nullptr;
5504
5505 /*
5506 key_cmp_if_same() compares table->record[0] against 'key'.
5507 In parts it uses table->record[0] directly, in parts it uses
5508 field objects with their local pointers into table->record[0].
5509 If 'buf' is distinct from table->record[0], we need to move
5510 all record references. This is table->record[0] itself and
5511 the field pointers of the fields used in this key.
5512 */
5513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 349 times.
349 if (ptrdiff) {
5514 save_record_0 = table->record[0];
5515 table->record[0] = buf;
5516 key_info = table->key_info + active_index;
5517 key_part = key_info->key_part;
5518 key_part_end = key_part + key_info->user_defined_key_parts;
5519 for (; key_part < key_part_end; key_part++) {
5520 assert(key_part->field);
5521 key_part->field->move_field_offset(ptrdiff);
5522 }
5523 }
5524
5525
3/4
✓ Branch 0 taken 349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 324 times.
349 if (key_cmp_if_same(table, key, active_index, keylen))
5526 25 error = HA_ERR_END_OF_FILE;
5527
5528 /* Move back if necessary. */
5529
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 349 times.
349 if (ptrdiff) {
5530 table->record[0] = save_record_0;
5531 for (key_part = key_info->key_part; key_part < key_part_end; key_part++)
5532 key_part->field->move_field_offset(-ptrdiff);
5533 }
5534 }
5535 488 return error;
5536 488 }
5537
5538 // Updates the global table stats with the TABLE this handler represents.
5539 47561 void handler::update_global_table_stats() {
5540
4/4
✓ Branch 0 taken 41381 times.
✓ Branch 1 taken 6180 times.
✓ Branch 2 taken 30375 times.
✓ Branch 3 taken 11006 times.
47561 if (!rows_read && !rows_changed) return; // Nothing to update.
5541 // table_cache_key is db_name + '\0' + table_name + '\0'.
5542
3/6
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17186 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 17186 times.
17186 if (!table->s || !table->s->table_cache_key.str || !table->s->table_name.str)
5543 return;
5544
5545 // [db] + '.' + [table]
5546
1/2
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
17186 std::string key{table->s->table_cache_key.str};
5547
1/2
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
17186 key.append(1, '.');
5548
1/2
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
17186 key.append(table->s->table_name.str);
5549 17186 key.shrink_to_fit();
5550
5551 17186 const ulonglong rows_changed_x_indexes =
5552
2/2
✓ Branch 0 taken 17107 times.
✓ Branch 1 taken 79 times.
17186 rows_changed * (table->s->keys ? table->s->keys : 1);
5553
5554
1/2
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
17186 mysql_mutex_lock(&LOCK_global_table_stats);
5555 // Gets the global table stats, creating one if necessary.
5556
1/2
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
17186 const auto &it = global_table_stats->find(key);
5557
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 16897 times.
17186 if (it == global_table_stats->cend()) {
5558
1/2
✓ Branch 0 taken 289 times.
✗ Branch 1 not taken.
289 global_table_stats->emplace(
5559 289 std::piecewise_construct, std::forward_as_tuple(key),
5560 289 std::forward_as_tuple(static_cast<int>(ht->db_type), rows_read,
5561 289 rows_changed, rows_changed_x_indexes));
5562 } else {
5563 16897 TABLE_STATS *const table_stats = &it->second;
5564 16897 table_stats->rows_read += rows_read;
5565 16897 table_stats->rows_changed += rows_changed;
5566 16897 table_stats->rows_changed_x_indexes += rows_changed_x_indexes;
5567 }
5568
1/2
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
17186 mysql_mutex_unlock(&LOCK_global_table_stats);
5569
1/2
✓ Branch 0 taken 17186 times.
✗ Branch 1 not taken.
17186 ha_thd()->diff_total_read_rows += rows_read;
5570 17186 rows_read = rows_changed = 0;
5571 17186 }
5572
5573 // Updates the global index stats with this handler's accumulated index reads.
5574 47561 void handler::update_global_index_stats() {
5575 // table_cache_key is db_name + '\0' + table_name + '\0'.
5576
3/6
✓ Branch 0 taken 47561 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47561 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 47561 times.
✗ Branch 5 not taken.
47561 if (!table || !table->s || !table->s->table_cache_key.str ||
5577
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 47561 times.
47561 !table->s->table_name.str)
5578 return;
5579
5580
2/2
✓ Branch 0 taken 161314 times.
✓ Branch 1 taken 47561 times.
208875 for (uint x = 0; x < table->s->keys; ++x) {
5581
2/2
✓ Branch 0 taken 7499 times.
✓ Branch 1 taken 153815 times.
161314 if (index_rows_read[x]) {
5582 // Rows were read using this index.
5583 7499 KEY *key_info = &table->key_info[x];
5584
5585
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7499 times.
7499 if (!key_info->name) continue;
5586
5587 // [db] + '.' + [table] + '.' + [index]
5588
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 std::string key{table->s->table_cache_key.str};
5589
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 key.append(1, '.');
5590
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 key.append(table->s->table_name.str);
5591
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 key.append(1, '.');
5592
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 key.append(key_info->name);
5593 7499 key.shrink_to_fit();
5594
5595
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 mysql_mutex_lock(&LOCK_global_index_stats);
5596
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 const auto &it = global_index_stats->find(key);
5597
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 7191 times.
7499 if (it == global_index_stats->cend()) {
5598
1/2
✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
308 global_index_stats->emplace(key, index_rows_read[x]);
5599 } else {
5600 7191 it->second += index_rows_read[x];
5601 }
5602
1/2
✓ Branch 0 taken 7499 times.
✗ Branch 1 not taken.
7499 mysql_mutex_unlock(&LOCK_global_index_stats);
5603 7499 index_rows_read[x] = 0;
5604 7499 }
5605 }
5606 }
5607
5608 /****************************************************************************
5609 ** Some general functions that isn't in the handler class
5610 ****************************************************************************/
5611
5612 /**
5613 Initiates table-file and calls appropriate database-creator.
5614
5615 @param thd Thread context.
5616 @param path Path to table file (without extension).
5617 @param db Database name.
5618 @param table_name Table name.
5619 @param create_info HA_CREATE_INFO describing table.
5620 @param update_create_info Indicates that create_info needs to be
5621 updated from table share.
5622 @param is_temp_table Indicates that this is temporary table (for
5623 cases when this info is not available from
5624 HA_CREATE_INFO).
5625 @param table_def Data-dictionary object describing table to
5626 be used for table creation. Can be adjusted
5627 by storage engine if it supports atomic DDL.
5628 For non-temporary tables these changes will
5629 be saved to the data-dictionary by this call.
5630
5631 @retval
5632 0 ok
5633 @retval
5634 1 error
5635 */
5636 329876 int ha_create_table(THD *thd, const char *path, const char *db,
5637 const char *table_name, HA_CREATE_INFO *create_info,
5638 const List<Create_field> *create_fields,
5639 bool update_create_info, bool is_temp_table,
5640 dd::Table *table_def) {
5641 329876 int error = 1;
5642
1/2
✓ Branch 0 taken 329879 times.
✗ Branch 1 not taken.
329876 TABLE table;
5643 char name_buff[FN_REFLEN];
5644 const char *name;
5645
1/2
✓ Branch 0 taken 329878 times.
✗ Branch 1 not taken.
329879 TABLE_SHARE share;
5646 #ifdef HAVE_PSI_TABLE_INTERFACE
5647 638969 bool temp_table = is_temp_table ||
5648
4/4
✓ Branch 0 taken 309091 times.
✓ Branch 1 taken 20787 times.
✓ Branch 2 taken 261588 times.
✓ Branch 3 taken 47503 times.
591466 (create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
5649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 261588 times.
261588 (strstr(path, tmp_file_prefix) != nullptr);
5650 #endif
5651
1/2
✓ Branch 0 taken 329880 times.
✗ Branch 1 not taken.
329878 DBUG_TRACE;
5652
5653
1/2
✓ Branch 0 taken 329879 times.
✗ Branch 1 not taken.
329880 init_tmp_table_share(thd, &share, db, 0, table_name, path, nullptr);
5654
5655
3/4
✓ Branch 0 taken 329880 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 329878 times.
329879 if (open_table_def(thd, &share, *table_def)) goto err;
5656
5657 #ifdef HAVE_PSI_TABLE_INTERFACE
5658
1/2
✓ Branch 0 taken 329877 times.
✗ Branch 1 not taken.
329878 share.m_psi = PSI_TABLE_CALL(get_table_share)(temp_table, &share);
5659 #endif
5660
5661 // When db_stat is 0, we can pass nullptr as dd::Table since it won't be used.
5662 329877 destroy(&table);
5663
3/4
✓ Branch 0 taken 329878 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 249 times.
✓ Branch 3 taken 329629 times.
329877 if (open_table_from_share(thd, &share, "", 0, (uint)READ_ALL, 0, &table, true,
5664 nullptr)) {
5665 #ifdef HAVE_PSI_TABLE_INTERFACE
5666 PSI_TABLE_CALL(drop_table_share)
5667
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
249 (temp_table, db, strlen(db), table_name, strlen(table_name));
5668 #endif
5669 249 goto err;
5670 }
5671
5672
3/4
✓ Branch 0 taken 50747 times.
✓ Branch 1 taken 278882 times.
✓ Branch 2 taken 50747 times.
✗ Branch 3 not taken.
329629 if (update_create_info) update_create_info_from_table(create_info, &table);
5673
5674 /*
5675 Updating field definitions in 'table' with zip_dict_name values
5676 from 'create_fields'
5677 */
5678
2/2
✓ Branch 0 taken 278882 times.
✓ Branch 1 taken 50747 times.
329629 if (create_fields != nullptr) {
5679
1/2
✓ Branch 0 taken 278882 times.
✗ Branch 1 not taken.
278882 table.update_compressed_columns_info(*create_fields);
5680 }
5681
5682
1/2
✓ Branch 0 taken 329629 times.
✗ Branch 1 not taken.
329629 name = get_canonical_filename(table.file, share.path.str, name_buff);
5683
5684
1/2
✓ Branch 0 taken 329570 times.
✗ Branch 1 not taken.
329629 error = table.file->ha_create(name, &table, create_info, table_def);
5685
5686
2/2
✓ Branch 0 taken 413 times.
✓ Branch 1 taken 329157 times.
329570 if (error) {
5687
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 table.file->print_error(error, MYF(0));
5688 #ifdef HAVE_PSI_TABLE_INTERFACE
5689 PSI_TABLE_CALL(drop_table_share)
5690
1/2
✓ Branch 0 taken 413 times.
✗ Branch 1 not taken.
413 (temp_table, db, strlen(db), table_name, strlen(table_name));
5691 #endif
5692 } else {
5693 /*
5694 We do post-create update only for engines supporting atomic DDL
5695 as only such engines are allowed to update dd::Table objects in
5696 handler::ha_create().
5697 The dd::Table objects for temporary tables are not stored in DD
5698 so do not need DD update.
5699 The dd::Table objects representing the DD tables themselves cannot
5700 be stored until the DD tables have been created in the SE.
5701 */
5702
2/2
✓ Branch 0 taken 261018 times.
✓ Branch 1 taken 19556 times.
280574 if (!((create_info->options & HA_LEX_CREATE_TMP_TABLE) || is_temp_table ||
5703
14/22
✓ Branch 0 taken 280574 times.
✓ Branch 1 taken 48583 times.
✓ Branch 2 taken 261018 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 261018 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 261018 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 261018 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 251396 times.
✓ Branch 11 taken 9622 times.
✓ Branch 12 taken 261018 times.
✓ Branch 13 taken 68139 times.
✓ Branch 14 taken 261018 times.
✓ Branch 15 taken 68139 times.
✓ Branch 16 taken 146971 times.
✓ Branch 17 taken 182186 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
861127 dd::get_dictionary()->is_dd_table_name(db, table_name)) &&
5704
2/2
✓ Branch 0 taken 146971 times.
✓ Branch 1 taken 104425 times.
251396 (table.file->ht->flags & HTON_SUPPORTS_ATOMIC_DDL)) {
5705
3/4
✓ Branch 0 taken 146971 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 146970 times.
146971 if (thd->dd_client()->update<dd::Table>(table_def)) error = 1;
5706 }
5707 }
5708
1/2
✓ Branch 0 taken 329570 times.
✗ Branch 1 not taken.
329570 (void)closefrm(&table, false);
5709 329821 err:
5710
1/2
✓ Branch 0 taken 329821 times.
✗ Branch 1 not taken.
329821 free_table_share(&share);
5711 329821 return error != 0;
5712 329821 }
5713
5714 /**
5715 Try to discover table from engine.
5716
5717 @note
5718 If found, import the serialized dictionary information.
5719
5720 @retval
5721 -1 Table did not exists
5722 @retval
5723 0 Table created ok
5724 @retval
5725 > 0 Error, table existed but could not be created
5726 */
5727 14340 int ha_create_table_from_engine(THD *thd, const char *db, const char *name) {
5728 int error;
5729 uchar *sdi_blob;
5730 size_t sdi_len;
5731
1/2
✓ Branch 0 taken 14340 times.
✗ Branch 1 not taken.
14340 DBUG_TRACE;
5732
3/8
✓ Branch 0 taken 14340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14340 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14340 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14340 DBUG_PRINT("enter", ("name '%s'.'%s'", db, name));
5733
5734
2/4
✓ Branch 0 taken 14340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14340 times.
✗ Branch 3 not taken.
14340 if ((error = ha_discover(thd, db, name, &sdi_blob, &sdi_len))) {
5735 /* Table could not be discovered and thus not created */
5736 14340 return error;
5737 }
5738
5739 /*
5740 Table was successfully discovered from SE, check if SDI need
5741 to be installed or if that has already been done by SE.
5742 No SDI blob returned from SE indicates it has installed
5743 the table definition for this table into DD itself.
5744 Otherwise, import the SDI based on the sdi_blob and sdi_len,
5745 which are set.
5746 */
5747 if (sdi_blob) {
5748 error = import_serialized_meta_data(sdi_blob, sdi_len, true);
5749 my_free(sdi_blob);
5750 if (error) return 2;
5751 }
5752
5753 dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
5754 const dd::Table *table_def = nullptr;
5755 if (thd->dd_client()->acquire(db, name, &table_def)) return 3;
5756
5757 if (table_def == nullptr) {
5758 my_error(ER_NO_SUCH_TABLE, MYF(0), db, name);
5759 return 3;
5760 }
5761
5762 char path[FN_REFLEN + 1];
5763 build_table_filename(path, sizeof(path) - 1, db, name, "", 0);
5764
5765 TABLE_SHARE share;
5766 init_tmp_table_share(thd, &share, db, 0, name, path, nullptr);
5767
5768 if (open_table_def(thd, &share, *table_def)) return 3;
5769
5770 TABLE table;
5771 // When db_stat is 0, we can pass nullptr as dd::Table since it won't be used.
5772 if (open_table_from_share(thd, &share, "", 0, 0, 0, &table, false, nullptr)) {
5773 free_table_share(&share);
5774 return 3;
5775 }
5776
5777 HA_CREATE_INFO create_info;
5778 update_create_info_from_table(&create_info, &table);
5779 create_info.table_options |= HA_OPTION_CREATE_FROM_ENGINE;
5780
5781 get_canonical_filename(table.file, path, path);
5782 std::unique_ptr<dd::Table> table_def_clone(table_def->clone());
5783 error =
5784 table.file->ha_create(path, &table, &create_info, table_def_clone.get());
5785 /*
5786 Note that the table_def_clone is not stored into the DD,
5787 necessary changes to the table_def should already have
5788 been done in ha_discover/import_serialized_meta_data.
5789 */
5790 (void)closefrm(&table, true);
5791
5792 return error != 0;
5793 14340 }
5794
5795 /**
5796 Try to find a table in a storage engine.
5797
5798 @param thd Thread handle
5799 @param db Normalized table schema name
5800 @param name Normalized table name.
5801 @param[out] exists Only valid if the function succeeded.
5802
5803 @retval true An error is found
5804 @retval false Success, check *exists
5805 */
5806
5807 583713 bool ha_check_if_table_exists(THD *thd, const char *db, const char *name,
5808 bool *exists) {
5809 583713 uchar *frmblob = nullptr;
5810 size_t frmlen;
5811
1/2
✓ Branch 0 taken 583715 times.
✗ Branch 1 not taken.
583713 DBUG_TRACE;
5812
5813
1/2
✓ Branch 0 taken 583715 times.
✗ Branch 1 not taken.
583715 *exists = !ha_discover(thd, db, name, &frmblob, &frmlen);
5814
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 583715 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
583715 if (*exists) my_free(frmblob);
5815
5816 583715 return false;
5817 583715 }
5818
5819 /**
5820 Check if a table specified by name is a system table.
5821
5822 @param db Database name for the table.
5823 @param table_name Table name to be checked.
5824 @param[out] is_sql_layer_system_table True if a system table belongs to
5825 sql_layer.
5826
5827 @return Operation status
5828 @retval true If the table name is a system table.
5829 @retval false If the table name is a user-level table.
5830 */
5831
5832 496839 static bool check_if_system_table(const char *db, const char *table_name,
5833 bool *is_sql_layer_system_table) {
5834 // Check if we have the system database name in the command.
5835
4/6
✓ Branch 0 taken 496843 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 496843 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 118066 times.
✓ Branch 5 taken 378777 times.
496839 if (!dd::get_dictionary()->is_dd_schema_name(db)) return false;
5836
5837 // Check if this is SQL layer system tables.
5838
5/8
✓ Branch 0 taken 378777 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 378777 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 378777 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 45518 times.
✓ Branch 7 taken 333259 times.
378777 if (dd::get_dictionary()->is_system_table_name(db, table_name))
5839 45518 *is_sql_layer_system_table = true;
5840
5841 378777 return true;
5842 }
5843
5844 /**
5845 @brief Check if a given table is a system table.
5846
5847 @details The primary purpose of introducing this function is to stop system
5848 tables to be created or being moved to undesired storage engines.
5849
5850 @todo There is another function called is_system_table_name() used by
5851 get_table_category(), which is used to set TABLE_SHARE table_category.
5852 It checks only a subset of table name like proc, event and time*.
5853 We cannot use below function in get_table_category(),
5854 as that affects locking mechanism. If we need to
5855 unify these functions, we need to fix locking issues generated.
5856
5857 @param hton Handlerton of new engine.
5858 @param db Database name.
5859 @param table_name Table name to be checked.
5860
5861 @return Operation status
5862 @retval true If the table name is a valid system table
5863 or if its a valid user table.
5864
5865 @retval false If the table name is a system table name
5866 and does not belong to engine specified
5867 in the command.
5868 */
5869
5870 496839 bool ha_check_if_supported_system_table(handlerton *hton, const char *db,
5871 const char *table_name) {
5872
1/2
✓ Branch 0 taken 496842 times.
✗ Branch 1 not taken.
496839 DBUG_TRACE;
5873 st_sys_tbl_chk_params check_params;
5874
5875 496842 check_params.is_sql_layer_system_table = false;
5876
3/4
✓ Branch 0 taken 496842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 118065 times.
✓ Branch 3 taken 378777 times.
496842 if (!check_if_system_table(db, table_name,
5877 &check_params.is_sql_layer_system_table))
5878 118065 return true; // It's a user table name
5879
5880 // Check if this is a system table and if some engine supports it.
5881 757554 check_params.status = check_params.is_sql_layer_system_table
5882
2/2
✓ Branch 0 taken 45518 times.
✓ Branch 1 taken 333259 times.
378777 ? st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE
5883 : st_sys_tbl_chk_params::NOT_KNOWN_SYSTEM_TABLE;
5884 378777 check_params.db_type = hton->db_type;
5885 378777 check_params.table_name = table_name;
5886 378777 check_params.db = db;
5887
1/2
✓ Branch 0 taken 378777 times.
✗ Branch 1 not taken.
378777 plugin_foreach(nullptr, check_engine_system_table_handlerton,
5888 MYSQL_STORAGE_ENGINE_PLUGIN, &check_params);
5889
5890 // SE does not support this system table.
5891
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 378655 times.
378777 if (check_params.status == st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE)
5892 122 return false;
5893
5894 // It's a system table or a valid user table.
5895 378655 return true;
5896 496842 }
5897
5898 /**
5899 @brief Called for each SE to check if given db, tablename is a system table.
5900
5901 @details The primary purpose of introducing this function is to stop system
5902 tables to be created or being moved to undesired storage engines.
5903
5904 @param plugin Points to specific SE.
5905 @param arg Is of type struct st_sys_tbl_chk_params.
5906
5907 @note
5908 args->status Indicates OUT param,
5909 see struct st_sys_tbl_chk_params definition for more info.
5910
5911 @return Operation status
5912 @retval true There was a match found.
5913 This will stop doing checks with other SE's.
5914
5915 @retval false There was no match found.
5916 Other SE's will be checked to find a match.
5917 */
5918 1118251 static bool check_engine_system_table_handlerton(THD *, plugin_ref plugin,
5919 void *arg) {
5920 1118251 st_sys_tbl_chk_params *check_params = (st_sys_tbl_chk_params *)arg;
5921 1118251 handlerton *hton = plugin_data<handlerton *>(plugin);
5922
5923 // Do we already know that the table is a system table?
5924
2/2
✓ Branch 0 taken 80298 times.
✓ Branch 1 taken 1037953 times.
1118251 if (check_params->status == st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE) {
5925 /*
5926 If this is the same SE specified in the command, we can
5927 simply ask the SE if it supports it stop the search regardless.
5928 */
5929
2/2
✓ Branch 0 taken 45518 times.
✓ Branch 1 taken 34780 times.
80298 if (hton->db_type == check_params->db_type) {
5930
4/4
✓ Branch 0 taken 45474 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 45396 times.
✓ Branch 3 taken 122 times.
90992 if (hton->is_supported_system_table &&
5931
2/2
✓ Branch 0 taken 45396 times.
✓ Branch 1 taken 78 times.
45474 hton->is_supported_system_table(
5932 check_params->db, check_params->table_name,
5933 45474 check_params->is_sql_layer_system_table))
5934 45396 check_params->status = st_sys_tbl_chk_params::SUPPORTED_SYSTEM_TABLE;
5935 45518 return true;
5936 }
5937 /*
5938 If this is a different SE, there is no point in asking the SE
5939 since we already know it's a system table and we don't care
5940 if it is supported or not.
5941 */
5942 34780 return false;
5943 }
5944
5945 /*
5946 We don't yet know if the table is a system table or not.
5947 We therefore must always ask the SE.
5948 */
5949
3/4
✓ Branch 0 taken 999777 times.
✓ Branch 1 taken 38176 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1037953 times.
2037730 if (hton->is_supported_system_table &&
5950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 999777 times.
999777 hton->is_supported_system_table(
5951 check_params->db, check_params->table_name,
5952 999777 check_params->is_sql_layer_system_table)) {
5953 /*
5954 If this is the same SE specified in the command, we know it's a
5955 supported system table and can stop the search.
5956 */
5957 if (hton->db_type == check_params->db_type) {
5958 check_params->status = st_sys_tbl_chk_params::SUPPORTED_SYSTEM_TABLE;
5959 return true;
5960 } else
5961 check_params->status = st_sys_tbl_chk_params::KNOWN_SYSTEM_TABLE;
5962 }
5963
5964 1037953 return false;
5965 }
5966
5967 103615 static bool rm_tmp_tables_handlerton(THD *thd, plugin_ref plugin, void *files) {
5968 103615 handlerton *hton = plugin_data<handlerton *>(plugin);
5969
5970
5/6
✓ Branch 0 taken 103364 times.
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 37671 times.
✓ Branch 3 taken 65693 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 103615 times.
141286 if (hton->state == SHOW_OPTION_YES && hton->rm_tmp_tables &&
5971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37671 times.
37671 hton->rm_tmp_tables(hton, thd, (List<LEX_STRING> *)files))
5972 return true;
5973
5974 103615 return false;
5975 }
5976
5977 /**
5978 Ask all SEs to drop all temporary tables which have been left from
5979 previous server run. Used on server start-up.
5980
5981 @param[in] thd Thread context.
5982 @param[in,out] files List of files in directories for temporary files
5983 which match tmp_file_prefix and thus can belong to
5984 temporary tables. If any SE recognizes some file as
5985 belonging to temporary table in this SE and deletes
5986 the file it is also supposed to remove file from
5987 this list.
5988 */
5989
5990 9418 bool ha_rm_tmp_tables(THD *thd, List<LEX_STRING> *files) {
5991 9418 return plugin_foreach(thd, rm_tmp_tables_handlerton,
5992 MYSQL_STORAGE_ENGINE_PLUGIN, files);
5993 }
5994
5995 /**
5996 Default implementation for handlerton::rm_tmp_tables() method which
5997 simply removes all files from "files" list which have one of SE's
5998 extensions. This implementation corresponds to default implementation
5999 of handler::delete_table() method.
6000 */
6001
6002 37671 bool default_rm_tmp_tables(handlerton *hton, THD *, List<LEX_STRING> *files) {
6003
1/2
✓ Branch 0 taken 37671 times.
✗ Branch 1 not taken.
37671 List_iterator<LEX_STRING> files_it(*files);
6004 LEX_STRING *file_path;
6005
6006
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37671 times.
37671 if (!hton->file_extensions) return false;
6007
6008
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 37671 times.
37717 while ((file_path = files_it++)) {
6009
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 const char *file_ext = fn_ext(file_path->str);
6010
6011
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 8 times.
77 for (const char **ext = hton->file_extensions; *ext; ext++) {
6012
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 31 times.
69 if (strcmp(file_ext, *ext) == 0) {
6013
5/6
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 36 times.
40 if (my_is_symlink(file_path->str, nullptr) &&
6014
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 test_if_data_home_dir(file_path->str)) {
6015 /*
6016 For safety reasons, if temporary table file is a symlink pointing
6017 to a file in the data directory, don't delete the file, delete
6018 symlink file only. It would be nicer to not delete symlinked files
6019 at all but MyISAM supports temporary tables with DATA
6020 DIRECTORY/INDEX DIRECTORY options.
6021 */
6022
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (void)mysql_file_delete(key_file_misc, file_path->str, MYF(0));
6023 } else
6024
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 (void)mysql_file_delete_with_symlink(key_file_misc, file_path->str,
6025 MYF(0));
6026
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
38 files_it.remove();
6027 38 break;
6028 }
6029 }
6030 }
6031 37671 return false;
6032 }
6033
6034 /*****************************************************************************
6035 Key cache handling.
6036
6037 This code is only relevant for ISAM/MyISAM tables
6038
6039 key_cache->cache may be 0 only in the case where a key cache is not
6040 initialized or when we where not able to init the key cache in a previous
6041 call to ha_init_key_cache() (probably out of memory)
6042 *****************************************************************************/
6043
6044 /**
6045 Init a key cache if it has not been initied before.
6046 */
6047 9761 int ha_init_key_cache(std::string_view, KEY_CACHE *key_cache) {
6048
1/2
✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
9761 DBUG_TRACE;
6049
6050
1/2
✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
9761 if (!key_cache->key_cache_inited) {
6051
1/2
✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
9761 mysql_mutex_lock(&LOCK_global_system_variables);
6052 9761 size_t tmp_buff_size = (size_t)key_cache->param_buff_size;
6053 9761 ulonglong tmp_block_size = key_cache->param_block_size;
6054 9761 ulonglong division_limit = key_cache->param_division_limit;
6055 9761 ulonglong age_threshold = key_cache->param_age_threshold;
6056
1/2
✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
9761 mysql_mutex_unlock(&LOCK_global_system_variables);
6057
1/2
✓ Branch 0 taken 9761 times.
✗ Branch 1 not taken.
9761 return !init_key_cache(key_cache, tmp_block_size, tmp_buff_size,
6058 9761 division_limit, age_threshold);
6059 }
6060 return 0;
6061 9761 }
6062
6063 /**
6064 Resize key cache.
6065 */
6066 101 int ha_resize_key_cache(KEY_CACHE *key_cache) {
6067
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 DBUG_TRACE;
6068
6069
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 2 times.
101 if (key_cache->key_cache_inited) {
6070
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 mysql_mutex_lock(&LOCK_global_system_variables);
6071 99 size_t tmp_buff_size = (size_t)key_cache->param_buff_size;
6072 99 ulonglong tmp_block_size = key_cache->param_block_size;
6073 99 ulonglong division_limit = key_cache->param_division_limit;
6074 99 ulonglong age_threshold = key_cache->param_age_threshold;
6075
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 mysql_mutex_unlock(&LOCK_global_system_variables);
6076 const int retval =
6077
2/4
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
99 resize_key_cache(key_cache, keycache_thread_var(), tmp_block_size,
6078 tmp_buff_size, division_limit, age_threshold);
6079 99 return !retval;
6080 }
6081 2 return 0;
6082 101 }
6083
6084 /**
6085 Move all tables from one key cache to another one.
6086 */
6087 8 int ha_change_key_cache(KEY_CACHE *old_key_cache, KEY_CACHE *new_key_cache) {
6088 8 mi_change_key_cache(old_key_cache, new_key_cache);
6089 8 return 0;
6090 }
6091
6092 struct st_discover_args {
6093 const char *db;
6094 const char *name;
6095 uchar **frmblob;
6096 size_t *frmlen;
6097 };
6098
6099 3828220 static bool discover_handlerton(THD *thd, plugin_ref plugin, void *arg) {
6100 3828220 st_discover_args *vargs = (st_discover_args *)arg;
6101 3828220 handlerton *hton = plugin_data<handlerton *>(plugin);
6102
4/6
✓ Branch 0 taken 3823574 times.
✓ Branch 1 taken 4646 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3823574 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3828220 times.
3828220 if (hton->state == SHOW_OPTION_YES && hton->discover &&
6103 (!(hton->discover(hton, thd, vargs->db, vargs->name, vargs->frmblob,
6104 vargs->frmlen))))
6105 return true;
6106
6107 3828220 return false;
6108 }
6109
6110 /**
6111 Try to discover one table from handler(s).
6112
6113 @param[in] thd Thread context.
6114 @param[in] db Schema of table
6115 @param[in] name Name of table
6116 @param[out] frmblob Pointer to blob with table definition.
6117 @param[out] frmlen Length of the returned table definition blob
6118
6119 @retval
6120 -1 Table did not exists
6121 @retval
6122 0 OK. Table could be discovered from SE.
6123 The *frmblob and *frmlen may be set if returning a blob
6124 which should be installed into data dictionary
6125 by the caller.
6126
6127 @retval
6128 >0 error. frmblob and frmlen may not be set
6129
6130 */
6131 598053 static int ha_discover(THD *thd, const char *db, const char *name,
6132 uchar **frmblob, size_t *frmlen) {
6133 598053 int error = -1; // Table does not exist in any handler
6134
1/2
✓ Branch 0 taken 598055 times.
✗ Branch 1 not taken.
598053 DBUG_TRACE;
6135
5/8
✓ Branch 0 taken 598055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 598055 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 598019 times.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
598055 DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
6136 598055 st_discover_args args = {db, name, frmblob, frmlen};
6137
6138
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 598050 times.
598055 if (is_prefix(name, tmp_file_prefix)) /* skip temporary tables */
6139 5 return error;
6140
6141
2/4
✓ Branch 0 taken 598050 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 598050 times.
598050 if (plugin_foreach(thd, discover_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
6142 &args))
6143 error = 0;
6144
6145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 598050 times.
598050 if (!error) {
6146 assert(!thd->status_var_aggregated);
6147 thd->status_var.ha_discover_count++;
6148 }
6149 598050 return error;
6150 598055 }
6151
6152 /**
6153 Call this function in order to give the handler the possibility
6154 to ask engine if there are any new tables that should be written to disk
6155 or any dropped tables that need to be removed from disk
6156 */
6157 struct st_find_files_args {
6158 const char *db;
6159 const char *path;
6160 const char *wild;
6161 bool dir;
6162 List<LEX_STRING> *files;
6163 };
6164
6165 static bool find_files_handlerton(THD *thd, plugin_ref plugin, void *arg) {
6166 st_find_files_args *vargs = (st_find_files_args *)arg;
6167 handlerton *hton = plugin_data<handlerton *>(plugin);
6168
6169 if (hton->state == SHOW_OPTION_YES && hton->find_files)
6170 if (hton->find_files(hton, thd, vargs->db, vargs->path, vargs->wild,
6171 vargs->dir, vargs->files))
6172 return true;
6173
6174 return false;
6175 }
6176
6177 int ha_find_files(THD *thd, const char *db, const char *path, const char *wild,
6178 bool dir, List<LEX_STRING> *files) {
6179 int error = 0;
6180 DBUG_TRACE;
6181 DBUG_PRINT("enter", ("db: '%s' path: '%s' wild: '%s' dir: %d", db, path,
6182 wild ? wild : "NULL", dir));
6183 st_find_files_args args = {db, path, wild, dir, files};
6184
6185 plugin_foreach(thd, find_files_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
6186 &args);
6187 /* The return value is not currently used */
6188 return error;
6189 }
6190
6191 /**
6192 Ask handler if the table exists in engine.
6193 @retval
6194 HA_ERR_NO_SUCH_TABLE Table does not exist
6195 @retval
6196 HA_ERR_TABLE_EXIST Table exists
6197 */
6198 struct st_table_exists_in_engine_args {
6199 const char *db;
6200 const char *name;
6201 int err;
6202 };
6203
6204 3364114 static bool table_exists_in_engine_handlerton(THD *thd, plugin_ref plugin,
6205 void *arg) {
6206 3364114 st_table_exists_in_engine_args *vargs = (st_table_exists_in_engine_args *)arg;
6207 3364114 handlerton *hton = plugin_data<handlerton *>(plugin);
6208
6209 3364114 int err = HA_ERR_NO_SUCH_TABLE;
6210
6211
3/4
✓ Branch 0 taken 3356297 times.
✓ Branch 1 taken 7817 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3356297 times.
3364114 if (hton->state == SHOW_OPTION_YES && hton->table_exists_in_engine)
6212 err = hton->table_exists_in_engine(hton, thd, vargs->db, vargs->name);
6213
6214 3364114 vargs->err = err;
6215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3364114 times.
3364114 if (vargs->err == HA_ERR_TABLE_EXIST) return true;
6216
6217 3364114 return false;
6218 }
6219
6220 316018 int ha_table_exists_in_engine(THD *thd, const char *db, const char *name) {
6221
1/2
✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
316018 DBUG_TRACE;
6222
5/8
✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 316018 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 315995 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
316019 DBUG_PRINT("enter", ("db: %s, name: %s", db, name));
6223 316018 st_table_exists_in_engine_args args = {db, name, HA_ERR_NO_SUCH_TABLE};
6224
1/2
✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
316018 plugin_foreach(thd, table_exists_in_engine_handlerton,
6225 MYSQL_STORAGE_ENGINE_PLUGIN, &args);
6226
5/8
✓ Branch 0 taken 316019 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 316019 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 315996 times.
✓ Branch 6 taken 23 times.
✗ Branch 7 not taken.
316019 DBUG_PRINT("exit", ("error: %d", args.err));
6227 316019 return args.err;
6228 316019 }
6229
6230 /*
6231 TODO: change this into a dynamic struct
6232 List<handlerton> does not work as
6233 1. binlog_end is called when MEM_ROOT is gone
6234 2. cannot work with thd MEM_ROOT as memory should be freed
6235 */
6236 #define MAX_HTON_LIST_ST 63
6237 struct hton_list_st {
6238 handlerton *hton[MAX_HTON_LIST_ST];
6239 uint sz;
6240 };
6241
6242 struct binlog_func_st {
6243 enum_binlog_func fn;
6244 void *arg;
6245 };
6246
6247 /** @brief
6248 Listing handlertons first to avoid recursive calls and deadlock
6249 */
6250 922397 static bool binlog_func_list(THD *, plugin_ref plugin, void *arg) {
6251 922397 hton_list_st *hton_list = (hton_list_st *)arg;
6252 922397 handlerton *hton = plugin_data<handlerton *>(plugin);
6253
3/4
✓ Branch 0 taken 921727 times.
✓ Branch 1 taken 670 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 921727 times.
922397 if (hton->state == SHOW_OPTION_YES && hton->binlog_func) {
6254 uint sz = hton_list->sz;
6255 if (sz == MAX_HTON_LIST_ST - 1) {
6256 /* list full */
6257 return false;
6258 }
6259 hton_list->hton[sz] = hton;
6260 hton_list->sz = sz + 1;
6261 }
6262 922397 return false;
6263 }
6264
6265 84025 static bool binlog_func_foreach(THD *thd, binlog_func_st *bfn) {
6266 hton_list_st hton_list;
6267 uint i, sz;
6268
6269 84025 hton_list.sz = 0;
6270
1/2
✓ Branch 0 taken 84025 times.
✗ Branch 1 not taken.
84025 plugin_foreach(thd, binlog_func_list, MYSQL_STORAGE_ENGINE_PLUGIN,
6271 &hton_list);
6272
6273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84025 times.
84025 for (i = 0, sz = hton_list.sz; i < sz; i++)
6274 hton_list.hton[i]->binlog_func(hton_list.hton[i], thd, bfn->fn, bfn->arg);
6275 84025 return false;
6276 }
6277
6278 29142 int ha_reset_logs(THD *thd) {
6279 29142 binlog_func_st bfn = {BFN_RESET_LOGS, nullptr};
6280
1/2
✓ Branch 0 taken 29142 times.
✗ Branch 1 not taken.
29142 binlog_func_foreach(thd, &bfn);
6281 29142 return 0;
6282 }
6283
6284 12600 void ha_reset_slave(THD *thd) {
6285 12600 binlog_func_st bfn = {BFN_RESET_SLAVE, nullptr};
6286
1/2
✓ Branch 0 taken 12600 times.
✗ Branch 1 not taken.
12600 binlog_func_foreach(thd, &bfn);
6287 12600 }
6288
6289 18790 void ha_binlog_wait(THD *thd) {
6290 18790 binlog_func_st bfn = {BFN_BINLOG_WAIT, nullptr};
6291
1/2
✓ Branch 0 taken 18790 times.
✗ Branch 1 not taken.
18790 binlog_func_foreach(thd, &bfn);
6292 18790 }
6293
6294 15036 int ha_binlog_index_purge_file(THD *thd, const char *file) {
6295 15036 binlog_func_st bfn = {BFN_BINLOG_PURGE_FILE, const_cast<char *>(file)};
6296
1/2
✓ Branch 0 taken 15036 times.
✗ Branch 1 not taken.
15036 binlog_func_foreach(thd, &bfn);
6297 15036 return 0;
6298 }
6299
6300 struct binlog_log_query_st {
6301 enum_binlog_command binlog_command;
6302 const char *query;
6303 size_t query_length;
6304 const char *db;
6305 const char *table_name;
6306 };
6307
6308 188876 static bool binlog_log_query_handlerton2(THD *thd, handlerton *hton,
6309 void *args) {
6310 188876 struct binlog_log_query_st *b = (struct binlog_log_query_st *)args;
6311
3/4
✓ Branch 0 taken 188815 times.
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 188815 times.
188876 if (hton->state == SHOW_OPTION_YES && hton->binlog_log_query)
6312 hton->binlog_log_query(hton, thd, b->binlog_command, b->query,
6313 b->query_length, b->db, b->table_name);
6314 188876 return false;
6315 }
6316
6317 103180 static bool binlog_log_query_handlerton(THD *thd, plugin_ref plugin,
6318 void *args) {
6319 103180 return binlog_log_query_handlerton2(thd, plugin_data<handlerton *>(plugin),
6320 103180 args);
6321 }
6322
6323 102179 void ha_binlog_log_query(THD *thd, handlerton *hton,
6324 enum_binlog_command binlog_command, const char *query,
6325 size_t query_length, const char *db,
6326 const char *table_name) {
6327 struct binlog_log_query_st b;
6328 102179 b.binlog_command = binlog_command;
6329 102179 b.query = query;
6330 102179 b.query_length = query_length;
6331 102179 b.db = db;
6332 102179 b.table_name = table_name;
6333
2/2
✓ Branch 0 taken 16483 times.
✓ Branch 1 taken 85696 times.
102179 if (hton == nullptr)
6334
1/2
✓ Branch 0 taken 16483 times.
✗ Branch 1 not taken.
16483 plugin_foreach(thd, binlog_log_query_handlerton,
6335 MYSQL_STORAGE_ENGINE_PLUGIN, &b);
6336 else
6337
1/2
✓ Branch 0 taken 85696 times.
✗ Branch 1 not taken.
85696 binlog_log_query_handlerton2(thd, hton, &b);
6338 102179 }
6339
6340 8457 int ha_binlog_end(THD *thd) {
6341 8457 binlog_func_st bfn = {BFN_BINLOG_END, nullptr};
6342
1/2
✓ Branch 0 taken 8457 times.
✗ Branch 1 not taken.
8457 binlog_func_foreach(thd, &bfn);
6343 8457 return 0;
6344 }
6345
6346 353138 static bool acl_notify_handlerton(THD *thd, plugin_ref plugin, void *data) {
6347 353138 handlerton *hton = plugin_data<handlerton *>(plugin);
6348
3/4
✓ Branch 0 taken 353084 times.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 353084 times.
353138 if (hton->state == SHOW_OPTION_YES && hton->acl_notify)
6349 hton->acl_notify(thd,
6350 static_cast<const class Acl_change_notification *>(data));
6351 353138 return false;
6352 }
6353
6354 32102 void ha_acl_notify(THD *thd, class Acl_change_notification *data) {
6355 32102 plugin_foreach(thd, acl_notify_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN, data);
6356 32102 }
6357
6358 /**
6359 Calculate cost of 'index only' scan for given index and number of records
6360
6361 @param keynr Index number
6362 @param records Estimated number of records to be retrieved
6363
6364 @note
6365 It is assumed that we will read through the whole key range and that all
6366 key blocks are half full (normally things are much better). It is also
6367 assumed that each time we read the next key from the index, the handler
6368 performs a random seek, thus the cost is proportional to the number of
6369 blocks read.
6370
6371 @return
6372 Estimated cost of 'index only' scan
6373 */
6374
6375 12041827 double handler::index_only_read_time(uint keynr, double records) {
6376 double read_time;
6377 12041827 uint keys_per_block =
6378 12041827 (stats.block_size / 2 /
6379 12041827 (table_share->key_info[keynr].key_length + ref_length) +
6380 1);
6381 12041827 read_time = ((double)(records + keys_per_block - 1) / (double)keys_per_block);
6382 12041827 return read_time;
6383 }
6384
6385 270439926 double handler::table_in_memory_estimate() const {
6386
4/6
✓ Branch 0 taken 66247383 times.
✓ Branch 1 taken 204192543 times.
✓ Branch 2 taken 66247488 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66247578 times.
✗ Branch 5 not taken.
270439926 assert(stats.table_in_mem_estimate == IN_MEMORY_ESTIMATE_UNKNOWN ||
6387 (stats.table_in_mem_estimate >= 0.0 &&
6388 stats.table_in_mem_estimate <= 1.0));
6389
6390 /*
6391 If the storage engine has supplied information about how much of the
6392 table that is currently in a memory buffer, then use this estimate.
6393 */
6394
2/2
✓ Branch 0 taken 66247553 times.
✓ Branch 1 taken 204192568 times.
270440121 if (stats.table_in_mem_estimate != IN_MEMORY_ESTIMATE_UNKNOWN)
6395 66247553 return stats.table_in_mem_estimate;
6396
6397 /*
6398 The storage engine has not provided any information about how much of
6399 this index is in memory, use an heuristic to produce an estimate.
6400 */
6401 204192568 return estimate_in_memory_buffer(stats.data_file_length);
6402 }
6403
6404 12044041 double handler::index_in_memory_estimate(uint keyno) const {
6405 12044041 const KEY *key = &table->key_info[keyno];
6406
6407 /*
6408 If the storage engine has supplied information about how much of the
6409 index that is currently in a memory buffer, then use this estimate.
6410 */
6411 12044041 const double est = key->in_memory_estimate();
6412
2/2
✓ Branch 0 taken 1942485 times.
✓ Branch 1 taken 10101598 times.
12044083 if (est != IN_MEMORY_ESTIMATE_UNKNOWN) return est;
6413
6414 /*
6415 The storage engine has not provided any information about how much of
6416 this index is in memory, use an heuristic to produce an estimate.
6417 */
6418 ulonglong file_length;
6419
6420 /*
6421 If the index is a clustered primary index, then use the data file
6422 size as estimate for how large the index is.
6423 */
6424
6/6
✓ Branch 0 taken 25747 times.
✓ Branch 1 taken 10075851 times.
✓ Branch 2 taken 21434 times.
✓ Branch 3 taken 4313 times.
✓ Branch 4 taken 21434 times.
✓ Branch 5 taken 10080164 times.
10101598 if (keyno == table->s->primary_key && primary_key_is_clustered())
6425 21434 file_length = stats.data_file_length;
6426 else
6427 10080164 file_length = stats.index_file_length;
6428
6429 10101598 return estimate_in_memory_buffer(file_length);
6430 }
6431
6432 214294226 double handler::estimate_in_memory_buffer(ulonglong table_index_size) const {
6433 /*
6434 The storage engine has not provided any information about how much of
6435 the table/index is in memory. In this case we use a heuristic:
6436
6437 - if the size of the table/index is less than 20 percent (pick any
6438 number) of the memory buffer, then the entire table/index is likely in
6439 memory.
6440 - if the size of the table/index is larger than the memory buffer, then
6441 assume nothing of the table/index is in memory.
6442 - if the size of the table/index is larger than 20 percent but less than
6443 the memory buffer size, then use a linear function of the table/index
6444 size that goes from 1.0 to 0.0.
6445 */
6446
6447 /*
6448 If the storage engine has information about the size of its
6449 memory buffer, then use this. Otherwise, assume that at least 100 MB
6450 of data can be cached in memory.
6451 */
6452 214294226 longlong memory_buf_size = get_memory_buffer_size();
6453
2/2
✓ Branch 0 taken 210675693 times.
✓ Branch 1 taken 3618529 times.
214294222 if (memory_buf_size <= 0) memory_buf_size = 100 * 1024 * 1024; // 100 MB
6454
6455 /*
6456 Upper limit for the relative size of a table to be considered
6457 entirely available in a memory buffer. If the actual table size is
6458 less than this we assume it is complete cached in a memory buffer.
6459 */
6460 214294222 const double table_index_in_memory_limit = 0.2;
6461
6462 /*
6463 Estimate for how much of the total memory buffer this table/index
6464 can occupy.
6465 */
6466 214294222 const double percent_of_mem =
6467 214294222 static_cast<double>(table_index_size) / memory_buf_size;
6468
6469 double in_mem_est;
6470
6471
2/2
✓ Branch 0 taken 213890769 times.
✓ Branch 1 taken 403453 times.
214294222 if (percent_of_mem < table_index_in_memory_limit) // Less than 20 percent
6472 213890769 in_mem_est = 1.0;
6473
2/2
✓ Branch 0 taken 2078 times.
✓ Branch 1 taken 401375 times.
403453 else if (percent_of_mem > 1.0) // Larger than buffer
6474 2078 in_mem_est = 0.0;
6475 else {
6476 /*
6477 The size of the table/index is larger than
6478 "table_index_in_memory_limit" * "memory_buf_size" but less than
6479 the total size of the memory buffer.
6480 */
6481 401375 in_mem_est = 1.0 - (percent_of_mem - table_index_in_memory_limit) /
6482 (1.0 - table_index_in_memory_limit);
6483 }
6484
2/4
✓ Branch 0 taken 214294225 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 214294225 times.
✗ Branch 3 not taken.
214294222 assert(in_mem_est >= 0.0 && in_mem_est <= 1.0);
6485
6486 214294225 return in_mem_est;
6487 }
6488
6489 212129766 Cost_estimate handler::table_scan_cost() {
6490 /*
6491 This function returns a Cost_estimate object. The function should be
6492 implemented in a way that allows the compiler to use "return value
6493 optimization" to avoid creating the temporary object for the return value
6494 and use of the copy constructor.
6495 */
6496
6497 212129766 const double io_cost = scan_time() * table->cost_model()->page_read_cost(1.0);
6498 212130033 Cost_estimate cost;
6499 212129855 cost.add_io(io_cost);
6500 212129918 return cost;
6501 }
6502
6503 12041830 Cost_estimate handler::index_scan_cost(uint index,
6504 double ranges [[maybe_unused]],
6505 double rows) {
6506 /*
6507 This function returns a Cost_estimate object. The function should be
6508 implemented in a way that allows the compiler to use "return value
6509 optimization" to avoid creating the temporary object for the return value
6510 and use of the copy constructor.
6511 */
6512
6513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12041830 times.
12041830 assert(ranges >= 0.0);
6514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12041830 times.
12041830 assert(rows >= 0.0);
6515
6516 12041830 const double io_cost = index_only_read_time(index, rows) *
6517 12041881 table->cost_model()->page_read_cost_index(index, 1.0);
6518 12041901 Cost_estimate cost;
6519 12041906 cost.add_io(io_cost);
6520 12041907 return cost;
6521 }
6522
6523 10893749 Cost_estimate handler::read_cost(uint index, double ranges, double rows) {
6524 /*
6525 This function returns a Cost_estimate object. The function should be
6526 implemented in a way that allows the compiler to use "return value
6527 optimization" to avoid creating the temporary object for the return value
6528 and use of the copy constructor.
6529 */
6530
6531
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10893749 times.
10893749 assert(ranges >= 0.0);
6532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10893749 times.
10893749 assert(rows >= 0.0);
6533
6534 const double io_cost =
6535 10893749 read_time(index, static_cast<uint>(ranges), static_cast<ha_rows>(rows)) *
6536 10893749 table->cost_model()->page_read_cost(1.0);
6537 10893837 Cost_estimate cost;
6538 10893845 cost.add_io(io_cost);
6539 10893836 return cost;
6540 }
6541
6542 9513939 double handler::page_read_cost(uint index [[maybe_unused]], double reads) {
6543 9513939 return table->cost_model()->page_read_cost(reads);
6544
6545 /////////////////
6546 // Other, non-page-based storage engine, may prefer to
6547 // override to;
6548 // return read_cost(index, 1, reads).total_cost();
6549
6550 // Longer term: We should avoid mixed usage of read_cost()
6551 // and page_read_cost() from the optimizer. Use only
6552 // one of these to get cost estimates comparable between different
6553 // access methods and call paths.
6554 }
6555
6556 7772495 double handler::worst_seek_times(double reads) {
6557 7772495 return table->cost_model()->page_read_cost(reads);
6558 }
6559
6560 /**
6561 Check if key has partially-covered columns
6562
6563 We can't use DS-MRR to perform range scans when the ranges are over
6564 partially-covered keys, because we'll not have full key part values
6565 (we'll have their prefixes from the index) and will not be able to check
6566 if we've reached the end the range.
6567
6568 @param table Table to check keys for
6569 @param keyno Key to check
6570
6571 @todo
6572 Allow use of DS-MRR in cases where the index has partially-covered
6573 components but they are not used for scanning.
6574
6575 @retval true Yes
6576 @retval false No
6577 */
6578
6579 10210777 static bool key_uses_partial_cols(TABLE *table, uint keyno) {
6580 10210777 KEY_PART_INFO *kp = table->key_info[keyno].key_part;
6581 10210777 KEY_PART_INFO *kp_end = kp + table->key_info[keyno].user_defined_key_parts;
6582
2/2
✓ Branch 0 taken 10244883 times.
✓ Branch 1 taken 10209252 times.
20454135 for (; kp != kp_end; kp++) {
6583
2/2
✓ Branch 0 taken 1525 times.
✓ Branch 1 taken 10243358 times.
10244883 if (!kp->field->part_of_key.is_set(keyno)) return true;
6584 }
6585 10209252 return false;
6586 }
6587
6588 /****************************************************************************
6589 * Default MRR implementation (MRR to non-MRR converter)
6590 ***************************************************************************/
6591
6592 /**
6593 Get cost and other information about MRR scan over a known list of ranges
6594
6595 Calculate estimated cost and other information about an MRR scan for given
6596 sequence of ranges.
6597
6598 @param keyno Index number
6599 @param seq Range sequence to be traversed
6600 @param seq_init_param First parameter for seq->init()
6601 @param n_ranges_arg Number of ranges in the sequence, or 0 if the caller
6602 can't efficiently determine it
6603 @param [in,out] bufsz IN: Size of the buffer available for use
6604 OUT: Size of the buffer that is expected to be actually
6605 used, or 0 if buffer is not needed.
6606 @param [in,out] flags A combination of HA_MRR_* flags
6607 @param [out] cost Estimated cost of MRR access
6608
6609 @note
6610 This method (or an overriding one in a derived class) must check for
6611 \c thd->killed and return HA_POS_ERROR if it is not zero. This is required
6612 for a user to be able to interrupt the calculation by killing the
6613 connection/query.
6614
6615 @retval
6616 HA_POS_ERROR Error or the engine is unable to perform the requested
6617 scan. Values of OUT parameters are undefined.
6618 @retval
6619 other OK, *cost contains cost of the scan, *bufsz and *flags
6620 contain scan parameters.
6621 */
6622
6623 10759204 ha_rows handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
6624 void *seq_init_param,
6625 uint n_ranges_arg [[maybe_unused]],
6626 uint *bufsz, uint *flags,
6627 Cost_estimate *cost) {
6628 KEY_MULTI_RANGE range;
6629 range_seq_t seq_it;
6630 10759204 ha_rows rows, total_rows = 0;
6631 10759204 uint n_ranges = 0;
6632
1/2
✓ Branch 0 taken 10759229 times.
✗ Branch 1 not taken.
10759204 THD *thd = current_thd;
6633
6634 /* Default MRR implementation doesn't need buffer */
6635 10759229 *bufsz = 0;
6636
6637
3/4
✓ Branch 0 taken 10759364 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10759363 times.
10759229 DBUG_EXECUTE_IF("bug13822652_2", thd->killed = THD::KILL_QUERY;);
6638
6639
1/2
✓ Branch 0 taken 10759350 times.
✗ Branch 1 not taken.
10759364 seq_it = seq->init(seq_init_param, n_ranges, *flags);
6640
3/4
✓ Branch 0 taken 21561534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10802231 times.
✓ Branch 3 taken 10759303 times.
21561547 while (!seq->next(seq_it, &range)) {
6641
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10802267 times.
10802231 if (unlikely(thd->killed != 0)) return HA_POS_ERROR;
6642
6643 10802267 n_ranges++;
6644 key_range *min_endp, *max_endp;
6645
2/2
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 10801624 times.
10802267 if (range.range_flag & GEOM_FLAG) {
6646 643 min_endp = &range.start_key;
6647 643 max_endp = nullptr;
6648 } else {
6649
2/2
✓ Branch 0 taken 10793439 times.
✓ Branch 1 taken 8185 times.
10801624 min_endp = range.start_key.length ? &range.start_key : nullptr;
6650
2/2
✓ Branch 0 taken 626747 times.
✓ Branch 1 taken 10174877 times.
10801624 max_endp = range.end_key.length ? &range.end_key : nullptr;
6651 }
6652
6653 /*
6654 Return HA_POS_ERROR if the specified keyno is not capable of
6655 serving the specified range request. The cases checked for are:
6656
6657 1) The range contain NULL values and the specified index will
6658 fallback to do a full table scan if it find NULLs in the keys.
6659 2) The range does not specify all key parts and the key
6660 cannot provide partial key searches.
6661 */
6662
3/4
✓ Branch 0 taken 3804 times.
✓ Branch 1 taken 10798463 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10802267 times.
10806071 if (range.range_flag & NULL_RANGE && // 1)
6663
2/4
✓ Branch 0 taken 3804 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3804 times.
3804 table->file->index_flags(keyno, 0, false) & HA_TABLE_SCAN_ON_NULL) {
6664 // The NULL_RANGE will result in a full TABLE_SCAN, reject it.
6665 return HA_POS_ERROR;
6666 }
6667
2/2
✓ Branch 0 taken 596716 times.
✓ Branch 1 taken 10205551 times.
10802267 if (!(range.range_flag & EQ_RANGE) || // 2)
6668
2/2
✓ Branch 0 taken 179260 times.
✓ Branch 1 taken 417456 times.
596716 range.start_key.length < table->key_info[keyno].key_length) {
6669 // A full EQ-range was not specified, reject if not OK by index.
6670
3/4
✓ Branch 0 taken 10384763 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 10384747 times.
10384811 if (index_flags(keyno, 0, false) & HA_ONLY_WHOLE_INDEX) {
6671 16 return HA_POS_ERROR;
6672 }
6673 }
6674
6675 /*
6676 Get the number of rows in the range. This is done by calling
6677 records_in_range() unless:
6678
6679 1) The index is unique.
6680 There cannot be more than one matching row, so 1 is
6681 assumed. Note that it is possible that the correct number
6682 is actually 0, so the row estimate may be too high in this
6683 case. Also note: ranges of the form "x IS NULL" may have more
6684 than 1 matching row so records_in_range() is called for these.
6685 2) SKIP_RECORDS_IN_RANGE will be set when skip_records_in_range or
6686 use_index_statistics are true.
6687 Ranges of the form "x IS NULL" will not use index statistics
6688 because the number of rows with this value are likely to be
6689 very different than the values in the index statistics.
6690
6691 Note: With SKIP_RECORDS_IN_RANGE, use Index statistics if:
6692 a) Index statistics is available.
6693 b) The range is an equality range but the index is either not
6694 unique or all of the keyparts are not used.
6695 */
6696 10802203 int keyparts_used = 0;
6697
2/2
✓ Branch 0 taken 144060 times.
✓ Branch 1 taken 10658143 times.
10802203 if ((range.range_flag & UNIQUE_RANGE) && // 1)
6698
2/2
✓ Branch 0 taken 143536 times.
✓ Branch 1 taken 524 times.
144060 !(range.range_flag & NULL_RANGE))
6699 143536 rows = 1; /* there can be at most one row */
6700
2/2
✓ Branch 0 taken 1247 times.
✓ Branch 1 taken 10657420 times.
10658667 else if (range.range_flag & SKIP_RECORDS_IN_RANGE && // 2)
6701
2/2
✓ Branch 0 taken 1246 times.
✓ Branch 1 taken 1 times.
1247 !(range.range_flag & NULL_RANGE)) {
6702 3708 if ((range.range_flag & EQ_RANGE) &&
6703
7/8
✓ Branch 0 taken 1216 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 1216 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1082 times.
✓ Branch 5 taken 134 times.
✓ Branch 6 taken 1082 times.
✓ Branch 7 taken 164 times.
2462 (keyparts_used = my_count_bits(range.start_key.keypart_map)) &&
6704 1216 table->key_info[keyno].has_records_per_key(keyparts_used - 1)) {
6705 1082 rows = static_cast<ha_rows>(
6706 1082 table->key_info[keyno].records_per_key(keyparts_used - 1));
6707 } else {
6708 /*
6709 Since records_in_range has not been called, set the rows to 1.
6710 FORCE INDEX has been used, cost model values will be ignored anyway.
6711 */
6712 164 rows = 1;
6713 }
6714 } else {
6715
2/6
✓ Branch 0 taken 10657429 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10657429 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10657421 DBUG_EXECUTE_IF("crash_records_in_range", DBUG_SUICIDE(););
6716
3/4
✓ Branch 0 taken 8187 times.
✓ Branch 1 taken 10649242 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8187 times.
10657429 assert(min_endp || max_endp);
6717
1/2
✓ Branch 0 taken 10657430 times.
✗ Branch 1 not taken.
10657429 rows = table->pos_in_table_list->is_derived_unfinished_materialization()
6718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10657430 times.
10657430 ? HA_POS_ERROR
6719
1/2
✓ Branch 0 taken 10657433 times.
✗ Branch 1 not taken.
10657430 : this->records_in_range(keyno, min_endp, max_endp);
6720
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 10657415 times.
10657433 if (rows == HA_POS_ERROR) {
6721 /* Can't scan one range => can't do MRR scan at all */
6722 18 return HA_POS_ERROR;
6723 }
6724 }
6725 10802197 total_rows += rows;
6726 }
6727
6728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10759303 times.
10759303 assert(total_rows != HA_POS_ERROR);
6729 {
6730 10759303 const Cost_model_table *const cost_model = table->cost_model();
6731
6732 /* The following calculation is the same as in multi_range_read_info(): */
6733 10759285 *flags |= (HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SUPPORT_SORTED);
6734
6735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10759260 times.
10759285 assert(cost->is_zero());
6736
2/2
✓ Branch 0 taken 226802 times.
✓ Branch 1 taken 10532458 times.
10759260 if (*flags & HA_MRR_INDEX_ONLY)
6737
1/2
✓ Branch 0 taken 226802 times.
✗ Branch 1 not taken.
226802 *cost = index_scan_cost(keyno, static_cast<double>(n_ranges),
6738 static_cast<double>(total_rows));
6739 else
6740
1/2
✓ Branch 0 taken 10532507 times.
✗ Branch 1 not taken.
10532458 *cost = read_cost(keyno, static_cast<double>(n_ranges),
6741 static_cast<double>(total_rows));
6742 10759284 cost->add_cpu(
6743 10759309 cost_model->row_evaluate_cost(static_cast<double>(total_rows)) + 0.01);
6744 }
6745 10759301 return total_rows;
6746 }
6747
6748 /**
6749 Get cost and other information about MRR scan over some sequence of ranges
6750
6751 Calculate estimated cost and other information about an MRR scan for some
6752 sequence of ranges.
6753
6754 The ranges themselves will be known only at execution phase. When this
6755 function is called we only know number of ranges and a (rough) E(#records)
6756 within those ranges.
6757
6758 Currently this function is only called for "n-keypart singlepoint" ranges,
6759 i.e. each range is "keypart1=someconst1 AND ... AND keypartN=someconstN"
6760
6761 The flags parameter is a combination of those flags: HA_MRR_SORTED,
6762 HA_MRR_INDEX_ONLY, HA_MRR_NO_ASSOCIATION, HA_MRR_LIMITS.
6763
6764 @param keyno Index number
6765 @param n_ranges Estimated number of ranges (i.e. intervals) in the
6766 range sequence.
6767 @param n_rows Estimated total number of records contained within all
6768 of the ranges
6769 @param [in,out] bufsz IN: Size of the buffer available for use
6770 OUT: Size of the buffer that will be actually used, or
6771 0 if buffer is not needed.
6772 @param [in,out] flags A combination of HA_MRR_* flags
6773 @param [out] cost Estimated cost of MRR access
6774
6775 @retval
6776 0 OK, *cost contains cost of the scan, *bufsz and *flags contain scan
6777 parameters.
6778 @retval
6779 other Error or can't perform the requested scan
6780 */
6781
6782 5452 ha_rows handler::multi_range_read_info(uint keyno, uint n_ranges, uint n_rows,
6783 uint *bufsz, uint *flags,
6784 Cost_estimate *cost) {
6785 5452 *bufsz = 0; /* Default implementation doesn't need a buffer */
6786
6787 5452 *flags |= HA_MRR_USE_DEFAULT_IMPL;
6788 5452 *flags |= HA_MRR_SUPPORT_SORTED;
6789
6790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5452 times.
5452 assert(cost->is_zero());
6791
6792 /* Produce the same cost as non-MRR code does */
6793
2/2
✓ Branch 0 taken 1884 times.
✓ Branch 1 taken 3568 times.
5452 if (*flags & HA_MRR_INDEX_ONLY)
6794 1884 *cost = index_scan_cost(keyno, n_ranges, n_rows);
6795 else
6796 3568 *cost = read_cost(keyno, n_ranges, n_rows);
6797 5452 return 0;
6798 }
6799
6800 /**
6801 Initialize the MRR scan.
6802
6803 This function may do heavyweight scan
6804 initialization like row prefetching/sorting/etc (NOTE: but better not do
6805 it here as we may not need it, e.g. if we never satisfy WHERE clause on
6806 previous tables. For many implementations it would be natural to do such
6807 initializations in the first multi_read_range_next() call)
6808
6809 mode is a combination of the following flags: HA_MRR_SORTED,
6810 HA_MRR_INDEX_ONLY, HA_MRR_NO_ASSOCIATION
6811
6812 @param seq_funcs Range sequence to be traversed
6813 @param seq_init_param First parameter for seq->init()
6814 @param n_ranges Number of ranges in the sequence
6815 @param mode Flags, see the description section for the details
6816 @param buf INOUT: memory buffer to be used
6817
6818 @note
6819 One must have called index_init() before calling this function. Several
6820 multi_range_read_init() calls may be made in course of one query.
6821
6822 Until WL#2623 is done (see its text, section 3.2), the following will
6823 also hold:
6824 The caller will guarantee that if "seq->init == mrr_ranges_array_init"
6825 then seq_init_param is an array of n_ranges KEY_MULTI_RANGE structures.
6826 This property will only be used by NDB handler until WL#2623 is done.
6827
6828 Buffer memory management is done according to the following scenario:
6829 The caller allocates the buffer and provides it to the callee by filling
6830 the members of HANDLER_BUFFER structure.
6831 The callee consumes all or some fraction of the provided buffer space, and
6832 sets the HANDLER_BUFFER members accordingly.
6833 The callee may use the buffer memory until the next multi_range_read_init()
6834 call is made, all records have been read, or until index_end() call is
6835 made, whichever comes first.
6836
6837 @retval 0 OK
6838 @retval 1 Error
6839 */
6840
6841 10739119 int handler::multi_range_read_init(RANGE_SEQ_IF *seq_funcs,
6842 void *seq_init_param, uint n_ranges,
6843 uint mode,
6844 HANDLER_BUFFER *buf [[maybe_unused]]) {
6845
1/2
✓ Branch 0 taken 10739241 times.
✗ Branch 1 not taken.
10739119 DBUG_TRACE;
6846
1/2
✓ Branch 0 taken 10739226 times.
✗ Branch 1 not taken.
10739241 mrr_iter = seq_funcs->init(seq_init_param, n_ranges, mode);
6847 10739226 mrr_funcs = *seq_funcs;
6848 10739226 mrr_is_output_sorted = mode & HA_MRR_SORTED;
6849 10739226 mrr_have_range = false;
6850 10739253 return 0;
6851 10739226 }
6852
6853 13979626 int handler::ha_multi_range_read_next(char **range_info) {
6854 int result;
6855
1/2
✓ Branch 0 taken 13979686 times.
✗ Branch 1 not taken.
13979626 DBUG_TRACE;
6856
6857 // Set status for the need to update generated fields
6858 13979686 m_update_generated_read_fields = table->has_gcol();
6859
6860
1/2
✓ Branch 0 taken 13979703 times.
✗ Branch 1 not taken.
13979661 result = multi_range_read_next(range_info);
6861
4/4
✓ Branch 0 taken 3442967 times.
✓ Branch 1 taken 10536736 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 3442921 times.
13979703 if (!result && m_update_generated_read_fields) {
6862 46 result =
6863
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 update_generated_read_fields(table->record[0], table, active_index);
6864 46 m_update_generated_read_fields = false;
6865 }
6866 13979703 table->set_row_status_from_handler(result);
6867 13979705 return result;
6868 13979703 }
6869
6870 /**
6871 Get next record in MRR scan
6872
6873 Default MRR implementation: read the next record
6874
6875 @param range_info OUT Undefined if HA_MRR_NO_ASSOCIATION flag is in effect
6876 Otherwise, the opaque value associated with the range
6877 that contains the returned record.
6878
6879 @retval 0 OK
6880 @retval other Error code
6881 */
6882
6883 13979785 int handler::multi_range_read_next(char **range_info) {
6884 13979785 int result = HA_ERR_END_OF_FILE;
6885 13979785 int range_res = 0;
6886 13979785 bool dup_found = false;
6887
1/2
✓ Branch 0 taken 13979860 times.
✗ Branch 1 not taken.
13979785 DBUG_TRACE;
6888 // For a multi-valued index the unique filter have to be used for correct
6889 // result
6890
3/4
✓ Branch 0 taken 849 times.
✓ Branch 1 taken 13979011 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 849 times.
13979860 assert(!(table->key_info[active_index].flags & HA_MULTI_VALUED_KEY) ||
6891 m_unique);
6892
6893
2/2
✓ Branch 0 taken 10538634 times.
✓ Branch 1 taken 3441226 times.
13979860 if (!mrr_have_range) {
6894 10538634 mrr_have_range = true;
6895 10538634 goto start;
6896 }
6897
6898 do {
6899 /*
6900 Do not call read_range_next() if its equality on a unique
6901 index.
6902 */
6903
2/2
✓ Branch 0 taken 119518 times.
✓ Branch 1 taken 3322041 times.
3441559 if (!((mrr_cur_range.range_flag & UNIQUE_RANGE) &&
6904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 119519 times.
119518 (mrr_cur_range.range_flag & EQ_RANGE))) {
6905
3/4
✓ Branch 0 taken 3321708 times.
✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3321708 times.
3322040 assert(!result || result == HA_ERR_END_OF_FILE);
6906
1/2
✓ Branch 0 taken 3322041 times.
✗ Branch 1 not taken.
3322040 result = read_range_next();
6907
2/4
✓ Branch 0 taken 3322041 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3322041 times.
3322041 DBUG_EXECUTE_IF("bug20162055_DEADLOCK", result = HA_ERR_LOCK_DEADLOCK;);
6908 /*
6909 On success check loop condition to filter duplicates, if needed.
6910 Exit on non-EOF error. Use next range on EOF error.
6911 */
6912
2/2
✓ Branch 0 taken 3106732 times.
✓ Branch 1 taken 215309 times.
3322041 if (!result) continue;
6913
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 215307 times.
215309 if (result != HA_ERR_END_OF_FILE) break;
6914 } else {
6915
2/4
✓ Branch 0 taken 119517 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 119517 times.
119519 if (was_semi_consistent_read()) goto scan_it_again;
6916 }
6917
6918 119517 start:
6919 /* Try the next range(s) until one matches a record. */
6920
3/4
✓ Branch 0 taken 21099710 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10563018 times.
✓ Branch 3 taken 10536692 times.
21099778 while (!(range_res = mrr_funcs.next(mrr_iter, &mrr_cur_range))) {
6921 10563018 scan_it_again:
6922
1/2
✓ Branch 0 taken 10563129 times.
✗ Branch 1 not taken.
21126036 result = read_range_first(
6923
2/2
✓ Branch 0 taken 10558407 times.
✓ Branch 1 taken 4611 times.
10563018 mrr_cur_range.start_key.keypart_map ? &mrr_cur_range.start_key
6924 : nullptr,
6925 10563018 mrr_cur_range.end_key.keypart_map ? &mrr_cur_range.end_key : nullptr,
6926
2/2
✓ Branch 0 taken 396127 times.
✓ Branch 1 taken 10166891 times.
10563018 mrr_cur_range.range_flag & EQ_RANGE, mrr_is_output_sorted);
6927
2/2
✓ Branch 0 taken 336809 times.
✓ Branch 1 taken 10226320 times.
10563129 if (result != HA_ERR_END_OF_FILE) break;
6928 }
6929 3443541 } while (((result == HA_ERR_END_OF_FILE) ||
6930
11/12
✓ Branch 0 taken 3443541 times.
✓ Branch 1 taken 10536692 times.
✓ Branch 2 taken 1062 times.
✓ Branch 3 taken 3442479 times.
✓ Branch 4 taken 1062 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 333 times.
✓ Branch 7 taken 729 times.
✓ Branch 8 taken 333 times.
✓ Branch 9 taken 10536692 times.
✓ Branch 10 taken 333 times.
✓ Branch 11 taken 13979900 times.
13980233 (m_unique && (dup_found = filter_dup_records()))) &&
6931 !range_res);
6932
6933 13979902 *range_info = mrr_cur_range.ptr;
6934 /*
6935 Last found record was a duplicate and we retrieved records from all
6936 ranges, so no more records can be returned.
6937 */
6938
3/4
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 13979870 times.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
13979902 if (dup_found && range_res) result = HA_ERR_END_OF_FILE;
6939
6940
5/8
✓ Branch 0 taken 13979887 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13979887 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 13979879 times.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
13979902 DBUG_PRINT("exit", ("handler::multi_range_read_next result %d", result));
6941 13979887 return result;
6942 13979887 }
6943
6944 /****************************************************************************
6945 * DS-MRR implementation
6946 ***************************************************************************/
6947
6948 /**
6949 DS-MRR: Initialize and start MRR scan
6950
6951 Initialize and start the MRR scan. Depending on the mode parameter, this
6952 may use default or DS-MRR implementation.
6953
6954 The DS-MRR implementation will use a second handler object (h2) for
6955 doing scan on the index:
6956 - on the first call to this function the h2 handler will be created
6957 and h2 will be opened using the same index as the main handler
6958 is set to use. The index scan on the main index will be closed
6959 and it will be re-opened to read records from the table using either
6960 no key or the primary key. The h2 handler will be deleted when
6961 reset() is called (which should happen on the end of the statement).
6962 - when dsmrr_close() is called the index scan on h2 is closed.
6963 - on following calls to this function one of the following must be valid:
6964 a. if dsmrr_close has been called:
6965 the main handler (h) must be open on an index, h2 will be opened
6966 using this index, and the index on h will be closed and
6967 h will be re-opened to read reads from the table using either
6968 no key or the primary key.
6969 b. dsmrr_close has not been called:
6970 h2 will already be open, the main handler h must be set up
6971 to read records from the table (handler->inited is RND) either
6972 using the primary index or using no index at all.
6973
6974 @param seq_funcs Interval sequence enumeration functions
6975 @param seq_init_param Interval sequence enumeration parameter
6976 @param n_ranges Number of ranges in the sequence.
6977 @param mode HA_MRR_* modes to use
6978 @param[in,out] buf Buffer to use
6979
6980 @retval 0 Ok, Scan started.
6981 @retval other Error
6982 */
6983
6984 10725576 int DsMrr_impl::dsmrr_init(RANGE_SEQ_IF *seq_funcs, void *seq_init_param,
6985 uint n_ranges, uint mode, HANDLER_BUFFER *buf) {
6986
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10725576 times.
10725576 assert(table != nullptr); // Verify init() called
6987
6988 uint elem_size;
6989 10725576 int retval = 0;
6990
1/2
✓ Branch 0 taken 10725705 times.
✗ Branch 1 not taken.
10725576 DBUG_TRACE;
6991 10725705 THD *const thd = table->in_use; // current THD
6992
6993
1/2
✓ Branch 0 taken 10725700 times.
✗ Branch 1 not taken.
10725705 if (!hint_key_state(thd, table->pos_in_table_list, h->active_index,
6994
4/4
✓ Branch 0 taken 10704418 times.
✓ Branch 1 taken 21282 times.
✓ Branch 2 taken 660669 times.
✓ Branch 3 taken 10065031 times.
21430118 MRR_HINT_ENUM, OPTIMIZER_SWITCH_MRR) ||
6995
2/2
✓ Branch 0 taken 639392 times.
✓ Branch 1 taken 10065026 times.
10704418 mode & (HA_MRR_USE_DEFAULT_IMPL | HA_MRR_SORTED)) // DS-MRR doesn't sort
6996 {
6997 660669 use_default_impl = true;
6998
1/2
✓ Branch 0 taken 660703 times.
✗ Branch 1 not taken.
660669 retval = h->handler::multi_range_read_init(seq_funcs, seq_init_param,
6999 n_ranges, mode, buf);
7000 660703 return retval;
7001 }
7002
7003 /*
7004 This assert will hit if we have pushed an index condition to the
7005 primary key index and then "change our mind" and use a different
7006 index for retrieving data with MRR. One of the following criteria
7007 must be true:
7008 1. We have not pushed an index condition on this handler.
7009 2. We have pushed an index condition and this is on the currently used
7010 index.
7011 3. We have pushed an index condition but this is not for the primary key.
7012 4. We have pushed an index condition and this has been transferred to
7013 the clone (h2) of the handler object.
7014 */
7015
3/10
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 10064799 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 232 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
10065031 assert(!h->pushed_idx_cond || h->pushed_idx_cond_keyno == h->active_index ||
7016 h->pushed_idx_cond_keyno != table->s->primary_key ||
7017 (h2 && h->pushed_idx_cond_keyno == h2->active_index));
7018
7019 10065031 rowids_buf = buf->buffer;
7020
7021 10065031 is_mrr_assoc = !(mode & HA_MRR_NO_ASSOCIATION);
7022
7023
2/2
✓ Branch 0 taken 4677 times.
✓ Branch 1 taken 10060354 times.
10065031 if (is_mrr_assoc) {
7024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4677 times.
4677 assert(!thd->status_var_aggregated);
7025 4677 table->in_use->status_var.ha_multi_range_read_init_count++;
7026 }
7027
7028 10065031 rowids_buf_end = buf->buffer_end;
7029 10065031 elem_size = h->ref_length + (int)is_mrr_assoc * sizeof(void *);
7030 10065031 rowids_buf_last =
7031 10065031 rowids_buf + ((rowids_buf_end - rowids_buf) / elem_size) * elem_size;
7032 10065031 rowids_buf_end = rowids_buf_last;
7033
7034 /*
7035 The DS-MRR scan uses a second handler object (h2) for doing the
7036 index scan. Create this by cloning the primary handler
7037 object. The h2 handler object is deleted when DsMrr_impl::reset()
7038 is called.
7039 */
7040
2/2
✓ Branch 0 taken 566 times.
✓ Branch 1 taken 10064465 times.
10065031 if (!h2) {
7041 handler *new_h2;
7042 /*
7043 ::clone() takes up a lot of stack, especially on 64 bit platforms.
7044 The constant 5 is an empiric result.
7045 @todo Is this still the case? Leave it as it is for now but could
7046 likely be removed?
7047 */
7048
2/4
✓ Branch 0 taken 566 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 566 times.
566 if (check_stack_overrun(thd, 5 * STACK_MIN_SIZE, (uchar *)&new_h2))
7049 return 1;
7050
7051
2/4
✓ Branch 0 taken 566 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 566 times.
566 if (!(new_h2 = h->clone(table->s->normalized_path.str, thd->mem_root)))
7052 return 1;
7053 566 h2 = new_h2; /* Ok, now can put it into h2 */
7054
1/2
✓ Branch 0 taken 566 times.
✗ Branch 1 not taken.
566 table->prepare_for_position();
7055 }
7056
7057 /*
7058 Open the index scan on h2 using the key from the primary handler.
7059 */
7060
2/2
✓ Branch 0 taken 10060633 times.
✓ Branch 1 taken 4398 times.
10065031 if (h2->active_index == MAX_KEY) {
7061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10060633 times.
10060633 assert(h->active_index != MAX_KEY);
7062 10060633 const uint mrr_keyno = h->active_index;
7063
7064
2/4
✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
10060633 if ((retval = h2->ha_external_lock(thd, h->get_lock_type()))) goto error;
7065
7066
2/4
✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
10060633 if ((retval = h2->extra(HA_EXTRA_KEYREAD))) goto error;
7067
7068
2/4
✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
10060633 if ((retval = h2->ha_index_init(mrr_keyno, false))) goto error;
7069
7070
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 10060580 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060633 times.
10060686 if ((table->key_info[mrr_keyno].flags & HA_MULTI_VALUED_KEY) &&
7071
2/4
✓ Branch 0 taken 53 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 53 times.
53 (retval = h2->ha_extra(HA_EXTRA_ENABLE_UNIQUE_RECORD_FILTER)))
7072 goto error; /* purecov: inspected */
7073
7074 // Transfer ICP from h to h2
7075
2/2
✓ Branch 0 taken 232 times.
✓ Branch 1 taken 10060401 times.
10060633 if (mrr_keyno == h->pushed_idx_cond_keyno) {
7076
2/4
✓ Branch 0 taken 232 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 232 times.
232 if (h2->idx_cond_push(mrr_keyno, h->pushed_idx_cond)) {
7077 retval = 1;
7078 goto error;
7079 }
7080 } else {
7081 // Cancel any potentially previously pushed index conditions
7082
1/2
✓ Branch 0 taken 10060396 times.
✗ Branch 1 not taken.
10060401 h2->cancel_pushed_idx_cond();
7083 }
7084 } else {
7085 /*
7086 h2 has already an open index. This happens when the DS-MRR scan
7087 is re-started without closing it first. In this case the primary
7088 handler must be used for reading records from the table, ie. it
7089 must not be opened for doing a new range scan. In this case
7090 the active_index must either not be set or be the primary key.
7091 */
7092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4398 times.
4398 assert(h->inited == handler::RND);
7093
3/4
✓ Branch 0 taken 4360 times.
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4360 times.
4398 assert(h->active_index == MAX_KEY ||
7094 h->active_index == table->s->primary_key);
7095 }
7096
7097 /*
7098 The index scan is now transferred to h2 and we can close the open
7099 index scan on the primary handler.
7100 */
7101
2/2
✓ Branch 0 taken 10060633 times.
✓ Branch 1 taken 4393 times.
10065026 if (h->inited == handler::INDEX) {
7102 /*
7103 Calling h->ha_index_end() will invoke dsmrr_close() for this object,
7104 which will close the index scan on h2. We need to keep it open, so
7105 temporarily move h2 out of the DsMrr object.
7106 */
7107 10060633 handler *save_h2 = h2;
7108 10060633 h2 = nullptr;
7109
1/2
✓ Branch 0 taken 10060633 times.
✗ Branch 1 not taken.
10060633 retval = h->ha_index_end();
7110 10060633 h2 = save_h2;
7111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10060633 times.
10060633 if (retval) goto error;
7112 }
7113
7114 /*
7115 Verify consistency between h and h2.
7116 */
7117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
10065026 assert(h->inited != handler::INDEX);
7118
3/4
✓ Branch 0 taken 4360 times.
✓ Branch 1 taken 10060666 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4360 times.
10065026 assert(h->active_index == MAX_KEY ||
7119 h->active_index == table->s->primary_key);
7120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
10065026 assert(h2->inited == handler::INDEX);
7121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
10065026 assert(h2->active_index != MAX_KEY);
7122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10065026 times.
10065026 assert(h->get_lock_type() == h2->get_lock_type());
7123
7124
2/4
✓ Branch 0 taken 10065026 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10065026 times.
10065026 if ((retval = h2->handler::multi_range_read_init(seq_funcs, seq_init_param,
7125 n_ranges, mode, buf)))
7126 goto error;
7127
7128
3/4
✓ Branch 0 taken 10065026 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10065025 times.
10065026 if ((retval = dsmrr_fill_buffer())) goto error;
7129
7130 /*
7131 If the above call has scanned through all intervals in *seq, then
7132 adjust *buf to indicate that the remaining buffer space will not be used.
7133 */
7134
2/2
✓ Branch 0 taken 10064920 times.
✓ Branch 1 taken 105 times.
10065025 if (dsmrr_eof) buf->end_of_used_area = rowids_buf_last;
7135
7136 /*
7137 h->inited == INDEX may occur when 'range checked for each record' is
7138 used.
7139 */
7140
4/6
✓ Branch 0 taken 10060632 times.
✓ Branch 1 taken 4393 times.
✓ Branch 2 taken 10060632 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10065025 times.
30186289 if ((h->inited != handler::RND) &&
7141
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10060632 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10060632 ((h->inited == handler::INDEX ? h->ha_index_end() : false) ||
7142
2/4
✓ Branch 0 taken 10060632 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10060632 times.
10060632 (h->ha_rnd_init(false)))) {
7143 retval = 1;
7144 goto error;
7145 }
7146
7147 10065025 use_default_impl = false;
7148 10065025 h->mrr_funcs = *seq_funcs;
7149
7150 10065025 return 0;
7151 1 error:
7152
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 h2->ha_index_or_rnd_end();
7153
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 h2->ha_external_lock(thd, F_UNLCK);
7154
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 h2->ha_close();
7155 1 destroy(h2);
7156 1 h2 = nullptr;
7157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(retval != 0);
7158 1 return retval;
7159 10725729 }
7160
7161 135737092 void DsMrr_impl::dsmrr_close() {
7162
1/2
✓ Branch 0 taken 135737125 times.
✗ Branch 1 not taken.
135737092 DBUG_TRACE;
7163
7164 // If there is an open index on h2, then close it
7165
4/4
✓ Branch 0 taken 10061224 times.
✓ Branch 1 taken 125675901 times.
✓ Branch 2 taken 10060632 times.
✓ Branch 3 taken 592 times.
135737125 if (h2 && h2->active_index != MAX_KEY) {
7166
1/2
✓ Branch 0 taken 10060632 times.
✗ Branch 1 not taken.
10060632 h2->ha_index_or_rnd_end();
7167
2/4
✓ Branch 0 taken 10060632 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10060632 times.
✗ Branch 3 not taken.
10060632 h2->ha_external_lock(current_thd, F_UNLCK);
7168 }
7169 135737125 use_default_impl = true;
7170 135737125 }
7171
7172 107847171 void DsMrr_impl::reset() {
7173
1/2
✓ Branch 0 taken 107850239 times.
✗ Branch 1 not taken.
107847171 DBUG_TRACE;
7174
7175
2/2
✓ Branch 0 taken 565 times.
✓ Branch 1 taken 107849674 times.
107850239 if (h2) {
7176 // Close any ongoing DS-MRR scan
7177
1/2
✓ Branch 0 taken 565 times.
✗ Branch 1 not taken.
565 dsmrr_close();
7178
7179 // Close and delete the h2 handler
7180
1/2
✓ Branch 0 taken 565 times.
✗ Branch 1 not taken.
565 h2->ha_close();
7181 565 destroy(h2);
7182 565 h2 = nullptr;
7183 }
7184 107850239 }
7185
7186 /**
7187 DS-MRR: Fill the buffer with rowids and sort it by rowid
7188
7189 {This is an internal function of DiskSweep MRR implementation}
7190 Scan the MRR ranges and collect ROWIDs (or {ROWID, range_id} pairs) into
7191 buffer. When the buffer is full or scan is completed, sort the buffer by
7192 rowid and return.
7193
7194 The function assumes that rowids buffer is empty when it is invoked.
7195
7196 @retval 0 OK, the next portion of rowids is in the buffer,
7197 properly ordered
7198 @retval other Error
7199 */
7200
7201 10065425 int DsMrr_impl::dsmrr_fill_buffer() {
7202 char *range_info;
7203 10065425 int res = 0;
7204
1/2
✓ Branch 0 taken 10065425 times.
✗ Branch 1 not taken.
10065425 DBUG_TRACE;
7205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10065425 times.
10065425 assert(rowids_buf < rowids_buf_end);
7206
7207 /*
7208 Set key_read to true since we only read fields from the index.
7209 This ensures that any virtual columns are read from index and are not
7210 attempted to be evaluated from base columns.
7211 (Do not use TABLE::set_keyread() since the MRR implementation operates
7212 with two handler objects, and set_keyread() would manipulate the keyread
7213 property of the wrong handler. MRR sets the handlers' keyread properties
7214 when initializing the MRR operation, independent of this call).
7215 */
7216 10065425 bool table_keyread_save = table->key_read;
7217 10065425 table->key_read = true;
7218
7219 10065425 rowids_buf_cur = rowids_buf;
7220 /*
7221 Do not use ha_multi_range_read_next() as it would call the engine's
7222 overridden multi_range_read_next() but the default implementation is wanted.
7223 */
7224
4/4
✓ Branch 0 taken 10086873 times.
✓ Branch 1 taken 399 times.
✓ Branch 2 taken 21847 times.
✓ Branch 3 taken 10065425 times.
20174145 while ((rowids_buf_cur < rowids_buf_end) &&
7225
3/4
✓ Branch 0 taken 10086873 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21847 times.
✓ Branch 3 taken 10065026 times.
10086873 !(res = h2->handler::multi_range_read_next(&range_info))) {
7226 /* Put rowid, or {rowid, range_id} pair into the buffer */
7227
1/2
✓ Branch 0 taken 21847 times.
✗ Branch 1 not taken.
21847 h2->position(table->record[0]);
7228 21847 memcpy(rowids_buf_cur, h2->ref, h2->ref_length);
7229 21847 rowids_buf_cur += h2->ref_length;
7230
7231
2/2
✓ Branch 0 taken 17542 times.
✓ Branch 1 taken 4305 times.
21847 if (is_mrr_assoc) {
7232 17542 memcpy(rowids_buf_cur, &range_info, sizeof(void *));
7233 17542 rowids_buf_cur += sizeof(void *);
7234 }
7235 }
7236
7237 // Restore key_read since the next read operation might read complete rows
7238 10065425 table->key_read = table_keyread_save;
7239
7240
4/4
✓ Branch 0 taken 10065026 times.
✓ Branch 1 taken 399 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 10065025 times.
10065425 if (res && res != HA_ERR_END_OF_FILE) return res;
7241 10065424 dsmrr_eof = (res == HA_ERR_END_OF_FILE);
7242
7243 /* Sort the buffer contents by rowid */
7244 10065424 uint elem_size = h->ref_length + (int)is_mrr_assoc * sizeof(void *);
7245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10065424 times.
10065424 assert((rowids_buf_cur - rowids_buf) % elem_size == 0);
7246
7247
1/2
✓ Branch 0 taken 10065424 times.
✗ Branch 1 not taken.
10065424 varlen_sort(
7248 rowids_buf, rowids_buf_cur, elem_size,
7249 148170 [this](const uchar *a, const uchar *b) { return h->cmp_ref(a, b) < 0; });
7250 10065424 rowids_buf_last = rowids_buf_cur;
7251 10065424 rowids_buf_cur = rowids_buf;
7252 10065424 return 0;
7253 10065425 }
7254
7255 /*
7256 DS-MRR implementation: multi_range_read_next() function
7257 */
7258
7259 13867758 int DsMrr_impl::dsmrr_next(char **range_info) {
7260 int res;
7261 13867758 uchar *cur_range_info = nullptr;
7262 uchar *rowid;
7263
7264
3/4
✓ Branch 0 taken 3781093 times.
✓ Branch 1 taken 10086665 times.
✓ Branch 2 taken 3781170 times.
✗ Branch 3 not taken.
13867758 if (use_default_impl) return h->handler::multi_range_read_next(range_info);
7265
7266 do {
7267
2/2
✓ Branch 0 taken 10065397 times.
✓ Branch 1 taken 21384 times.
10086781 if (rowids_buf_cur == rowids_buf_last) {
7268
2/2
✓ Branch 0 taken 10064998 times.
✓ Branch 1 taken 399 times.
10065397 if (dsmrr_eof) {
7269 10064998 res = HA_ERR_END_OF_FILE;
7270 10064998 goto end;
7271 }
7272
7273
1/2
✓ Branch 0 taken 399 times.
✗ Branch 1 not taken.
399 res = dsmrr_fill_buffer();
7274
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 399 times.
399 if (res) goto end;
7275 }
7276
7277 /* return eof if there are no rowids in the buffer after re-fill attempt */
7278
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 21775 times.
21783 if (rowids_buf_cur == rowids_buf_last) {
7279 8 res = HA_ERR_END_OF_FILE;
7280 8 goto end;
7281 }
7282 21775 rowid = rowids_buf_cur;
7283
7284
2/2
✓ Branch 0 taken 17470 times.
✓ Branch 1 taken 4305 times.
21775 if (is_mrr_assoc)
7285 17470 memcpy(&cur_range_info, rowids_buf_cur + h->ref_length, sizeof(uchar *));
7286
7287 21775 rowids_buf_cur += h->ref_length + sizeof(void *) * is_mrr_assoc;
7288
4/4
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 21606 times.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 21659 times.
21944 if (h2->mrr_funcs.skip_record &&
7289
3/4
✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✓ Branch 3 taken 79 times.
169 h2->mrr_funcs.skip_record(h2->mrr_iter, (char *)cur_range_info, rowid))
7290 116 continue;
7291
1/2
✓ Branch 0 taken 21685 times.
✗ Branch 1 not taken.
21659 res = h->ha_rnd_pos(table->record[0], rowid);
7292 21685 break;
7293 } while (true);
7294
7295
2/2
✓ Branch 0 taken 4305 times.
✓ Branch 1 taken 17380 times.
21685 if (is_mrr_assoc) {
7296 17380 memcpy(range_info, rowid + h->ref_length, sizeof(void *));
7297 }
7298 4305 end:
7299 10086691 return res;
7300 }
7301
7302 /*
7303 DS-MRR implementation: multi_range_read_info() function
7304 */
7305 4108 ha_rows DsMrr_impl::dsmrr_info(uint keyno, uint n_ranges, uint rows,
7306 uint *bufsz, uint *flags, Cost_estimate *cost) {
7307 ha_rows res [[maybe_unused]];
7308 4108 uint def_flags = *flags;
7309 4108 uint def_bufsz = *bufsz;
7310
7311 /* Get cost/flags/mem_usage of default MRR implementation */
7312
1/2
✓ Branch 0 taken 4108 times.
✗ Branch 1 not taken.
4108 res = h->handler::multi_range_read_info(keyno, n_ranges, rows, &def_bufsz,
7313 &def_flags, cost);
7314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4108 times.
4108 assert(!res);
7315
7316
3/4
✓ Branch 0 taken 4108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3550 times.
✓ Branch 3 taken 558 times.
8216 if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
7317
3/4
✓ Branch 0 taken 4108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3550 times.
✓ Branch 3 taken 558 times.
4108 choose_mrr_impl(keyno, rows, flags, bufsz, cost)) {
7318 /* Default implementation is chosen */
7319
3/8
✓ Branch 0 taken 3550 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3550 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3550 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3550 DBUG_PRINT("info", ("Default MRR implementation choosen"));
7320 3550 *flags = def_flags;
7321 3550 *bufsz = def_bufsz;
7322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3550 times.
3550 assert(*flags & HA_MRR_USE_DEFAULT_IMPL);
7323 } else {
7324 /* *flags and *bufsz were set by choose_mrr_impl */
7325
3/8
✓ Branch 0 taken 558 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 558 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 558 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
558 DBUG_PRINT("info", ("DS-MRR implementation choosen"));
7326 }
7327 4108 return 0;
7328 }
7329
7330 /*
7331 DS-MRR Implementation: multi_range_read_info_const() function
7332 */
7333
7334 10710006 ha_rows DsMrr_impl::dsmrr_info_const(uint keyno, RANGE_SEQ_IF *seq,
7335 void *seq_init_param, uint n_ranges,
7336 uint *bufsz, uint *flags,
7337 Cost_estimate *cost) {
7338 ha_rows rows;
7339 10710006 uint def_flags = *flags;
7340 10710006 uint def_bufsz = *bufsz;
7341 /* Get cost/flags/mem_usage of default MRR implementation */
7342
1/2
✓ Branch 0 taken 10710125 times.
✗ Branch 1 not taken.
10710006 rows = h->handler::multi_range_read_info_const(
7343 keyno, seq, seq_init_param, n_ranges, &def_bufsz, &def_flags, cost);
7344
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10710105 times.
10710125 if (rows == HA_POS_ERROR) {
7345 /* Default implementation can't perform MRR scan => we can't either */
7346 20 return rows;
7347 }
7348
7349 /*
7350 If HA_MRR_USE_DEFAULT_IMPL has been passed to us, that is an order to
7351 use the default MRR implementation (we need it for UPDATE/DELETE).
7352 Otherwise, make a choice based on cost and mrr* flags of
7353 @@optimizer_switch.
7354 */
7355
4/4
✓ Branch 0 taken 10709726 times.
✓ Branch 1 taken 379 times.
✓ Branch 2 taken 647919 times.
✓ Branch 3 taken 10062232 times.
21419877 if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
7356
3/4
✓ Branch 0 taken 10709772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647593 times.
✓ Branch 3 taken 10062179 times.
10709726 choose_mrr_impl(keyno, rows, flags, bufsz, cost)) {
7357
5/8
✓ Branch 0 taken 647930 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 647983 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 647979 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
647919 DBUG_PRINT("info", ("Default MRR implementation choosen"));
7358 647983 *flags = def_flags;
7359 647983 *bufsz = def_bufsz;
7360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 647983 times.
647983 assert(*flags & HA_MRR_USE_DEFAULT_IMPL);
7361 } else {
7362 /* *flags and *bufsz were set by choose_mrr_impl */
7363
3/8
✓ Branch 0 taken 10062179 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10062179 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10062179 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10062232 DBUG_PRINT("info", ("DS-MRR implementation choosen"));
7364 }
7365 10710137 return rows;
7366 }
7367
7368 /**
7369 DS-MRR Internals: Choose between Default MRR implementation and DS-MRR
7370
7371 Make the choice between using Default MRR implementation and DS-MRR.
7372 This function contains common functionality factored out of dsmrr_info()
7373 and dsmrr_info_const(). The function assumes that the default MRR
7374 implementation's applicability requirements are satisfied.
7375
7376 @param keyno Index number
7377 @param rows E(full rows to be retrieved)
7378 @param flags IN MRR flags provided by the MRR user
7379 OUT If DS-MRR is chosen, flags of DS-MRR implementation
7380 else the value is not modified
7381 @param bufsz IN If DS-MRR is chosen, buffer use of DS-MRR implementation
7382 else the value is not modified
7383 @param cost IN Cost of default MRR implementation
7384 OUT If DS-MRR is chosen, cost of DS-MRR scan
7385 else the value is not modified
7386
7387 @retval true Default MRR implementation should be used
7388 @retval false DS-MRR implementation should be used
7389 */
7390
7391 10713797 bool DsMrr_impl::choose_mrr_impl(uint keyno, ha_rows rows, uint *flags,
7392 uint *bufsz, Cost_estimate *cost) {
7393 bool res;
7394
1/2
✓ Branch 0 taken 10713869 times.
✗ Branch 1 not taken.
10713797 THD *thd = current_thd;
7395 10713869 TABLE_LIST *tl = table->pos_in_table_list;
7396 const bool mrr_on =
7397
1/2
✓ Branch 0 taken 10713931 times.
✗ Branch 1 not taken.
10713869 hint_key_state(thd, tl, keyno, MRR_HINT_ENUM, OPTIMIZER_SWITCH_MRR);
7398 const bool force_dsmrr_by_hints =
7399
3/4
✓ Branch 0 taken 10713972 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10713967 times.
✓ Branch 3 taken 5 times.
21427901 hint_key_state(thd, tl, keyno, MRR_HINT_ENUM, 0) ||
7400
3/4
✓ Branch 0 taken 10713970 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 10713939 times.
10713967 hint_table_state(thd, tl, BKA_HINT_ENUM, 0);
7401
7402
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26114 times.
26124 if (!(mrr_on || force_dsmrr_by_hints) ||
7403
2/2
✓ Branch 0 taken 10276932 times.
✓ Branch 1 taken 410929 times.
10687861 *flags & (HA_MRR_INDEX_ONLY | HA_MRR_SORTED) || // Unsupported by DS-MRR
7404
7/8
✓ Branch 0 taken 66370 times.
✓ Branch 1 taken 10210562 times.
✓ Branch 2 taken 66370 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 294 times.
✓ Branch 5 taken 66076 times.
✓ Branch 6 taken 10209252 times.
✓ Branch 7 taken 1525 times.
20487709 (keyno == table->s->primary_key && h->primary_key_is_clustered()) ||
7405
4/4
✓ Branch 0 taken 26124 times.
✓ Branch 1 taken 10687851 times.
✓ Branch 2 taken 504665 times.
✓ Branch 3 taken 10209231 times.
31638727 key_uses_partial_cols(table, keyno) ||
7406
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 10209245 times.
10209252 table->s->tmp_table != NO_TMP_TABLE) {
7407 /* Use the default implementation, don't modify args: See comments */
7408 504665 return true;
7409 }
7410
7411 /*
7412 If @@optimizer_switch has "mrr_cost_based" on, we should avoid
7413 using DS-MRR for queries where it is likely that the records are
7414 stored in memory. Since there is currently no way to determine
7415 this, we use a heuristic:
7416 a) if the storage engine has a memory buffer, DS-MRR is only
7417 considered if the table size is bigger than the buffer.
7418 b) if the storage engine does not have a memory buffer, DS-MRR is
7419 only considered if the table size is bigger than 100MB.
7420 c) Since there is an initial setup cost of DS-MRR, so it is only
7421 considered if at least 50 records will be read.
7422 */
7423
4/4
✓ Branch 0 taken 146697 times.
✓ Branch 1 taken 10062548 times.
✓ Branch 2 taken 146681 times.
✓ Branch 3 taken 10062564 times.
10355928 if (thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MRR_COST_BASED) &&
7424
2/2
✓ Branch 0 taken 146681 times.
✓ Branch 1 taken 16 times.
146697 !force_dsmrr_by_hints) {
7425 /*
7426 If the storage engine has a database buffer we use this as the
7427 minimum size the table should have before considering DS-MRR.
7428 */
7429
1/2
✓ Branch 0 taken 146681 times.
✗ Branch 1 not taken.
146681 longlong min_file_size = table->file->get_memory_buffer_size();
7430
2/2
✓ Branch 0 taken 51314 times.
✓ Branch 1 taken 95367 times.
146681 if (min_file_size == -1) {
7431 // No estimate for database buffer
7432 51314 min_file_size = 100 * 1024 * 1024; // 100 MB
7433 }
7434
7435 146681 if (table->file->stats.data_file_length <
7436
3/4
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 146484 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 197 times.
146681 static_cast<ulonglong>(min_file_size) ||
7437 rows <= 50)
7438 146484 return true; // Use the default implementation
7439 }
7440
7441 10062761 Cost_estimate dsmrr_cost;
7442
3/4
✓ Branch 0 taken 10062761 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 10062746 times.
10062761 if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
7443 15 return true;
7444
7445 /*
7446 If @@optimizer_switch has "mrr" on and "mrr_cost_based" off, then set cost
7447 of DS-MRR to be minimum of DS-MRR and Default implementations cost. This
7448 allows one to force use of DS-MRR whenever it is applicable without
7449 affecting other cost-based choices. Note that if MRR or BKA hint is
7450 specified, DS-MRR will be used regardless of cost.
7451 */
7452 const bool force_dsmrr =
7453
2/2
✓ Branch 0 taken 10062709 times.
✓ Branch 1 taken 37 times.
20125455 (force_dsmrr_by_hints ||
7454
2/2
✓ Branch 0 taken 10062512 times.
✓ Branch 1 taken 197 times.
10062709 !thd->optimizer_switch_flag(OPTIMIZER_SWITCH_MRR_COST_BASED));
7455
7456
6/6
✓ Branch 0 taken 10062549 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 10062499 times.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 10062696 times.
10062746 if (force_dsmrr && dsmrr_cost.total_cost() > cost->total_cost())
7457 50 dsmrr_cost = *cost;
7458
7459
6/6
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 10062549 times.
✓ Branch 2 taken 188 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 10062737 times.
✓ Branch 5 taken 9 times.
10062746 if (force_dsmrr || (dsmrr_cost.total_cost() <= cost->total_cost())) {
7460 10062737 *flags &= ~HA_MRR_USE_DEFAULT_IMPL; /* Use the DS-MRR implementation */
7461 10062737 *flags &= ~HA_MRR_SUPPORT_SORTED; /* We can't provide ordered output */
7462 10062737 *cost = dsmrr_cost;
7463 10062737 res = false;
7464 } else {
7465 /* Use the default MRR implementation */
7466 9 res = true;
7467 }
7468 10062746 return res;
7469 }
7470
7471 static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows,
7472 Cost_estimate *cost);
7473
7474 /**
7475 Get cost of DS-MRR scan
7476
7477 @param keynr Index to be used
7478 @param rows E(Number of rows to be scanned)
7479 @param flags Scan parameters (HA_MRR_* flags)
7480 @param buffer_size INOUT Buffer size
7481 @param cost OUT The cost
7482
7483 @retval false OK
7484 @retval true Error, DS-MRR cannot be used (the buffer is too small
7485 for even 1 rowid)
7486 */
7487
7488 10062761 bool DsMrr_impl::get_disk_sweep_mrr_cost(uint keynr, ha_rows rows, uint flags,
7489 uint *buffer_size,
7490 Cost_estimate *cost) {
7491 ha_rows rows_in_last_step;
7492 uint n_full_steps;
7493
7494 10062761 const uint elem_size =
7495
2/2
✓ Branch 0 taken 558 times.
✓ Branch 1 taken 10062203 times.
10062761 h->ref_length + sizeof(void *) * !(flags & HA_MRR_NO_ASSOCIATION);
7496 10062761 const ha_rows max_buff_entries = *buffer_size / elem_size;
7497
7498
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 10062746 times.
10062761 if (!max_buff_entries)
7499 15 return true; /* Buffer has not enough space for even 1 rowid */
7500
7501 /* Number of iterations we'll make with full buffer */
7502 10062746 n_full_steps = (uint)floor(rows2double(rows) / max_buff_entries);
7503
7504 /*
7505 Get numbers of rows we'll be processing in last iteration, with
7506 non-full buffer
7507 */
7508 10062746 rows_in_last_step = rows % max_buff_entries;
7509
7510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10062746 times.
10062746 assert(cost->is_zero());
7511
7512
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 10062684 times.
10062746 if (n_full_steps) {
7513
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 get_sort_and_sweep_cost(table, max_buff_entries, cost);
7514 62 cost->multiply(n_full_steps);
7515 } else {
7516 /*
7517 Adjust buffer size since only parts of the buffer will be used:
7518 1. Adjust record estimate for the last scan to reduce likelihood
7519 of needing more than one scan by adding 20 percent to the
7520 record estimate and by ensuring this is at least 100 records.
7521 2. If the estimated needed buffer size is lower than suggested by
7522 the caller then set it to the estimated buffer size.
7523 */
7524 const ha_rows keys_in_buffer =
7525 10062684 max<ha_rows>(static_cast<ha_rows>(1.2 * rows_in_last_step), 100);
7526 20125368 *buffer_size = min<ulong>(*buffer_size,
7527 10062684 static_cast<ulong>(keys_in_buffer) * elem_size);
7528 }
7529
7530 10062746 Cost_estimate last_step_cost;
7531
1/2
✓ Branch 0 taken 10062746 times.
✗ Branch 1 not taken.
10062746 get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost);
7532 10062746 (*cost) += last_step_cost;
7533
7534 /*
7535 Cost of memory is not included in the total_cost() function and
7536 thus will not be considered when comparing costs. Still, we
7537 record it in the cost estimate object for future use.
7538 */
7539 10062746 cost->add_mem(*buffer_size);
7540
7541 /* Total cost of all index accesses */
7542
1/2
✓ Branch 0 taken 10062746 times.
✗ Branch 1 not taken.
10062746 (*cost) += h->index_scan_cost(keynr, 1, static_cast<double>(rows));
7543
7544 /*
7545 Add CPU cost for processing records (see
7546 @handler::multi_range_read_info_const()).
7547 */
7548 10062746 cost->add_cpu(
7549 10062746 table->cost_model()->row_evaluate_cost(static_cast<double>(rows)));
7550 10062746 return false;
7551 }
7552
7553 /*
7554 Get cost of one sort-and-sweep step
7555
7556 SYNOPSIS
7557 get_sort_and_sweep_cost()
7558 table Table being accessed
7559 nrows Number of rows to be sorted and retrieved
7560 cost OUT The cost
7561
7562 DESCRIPTION
7563 Get cost of these operations:
7564 - sort an array of #nrows ROWIDs using qsort
7565 - read #nrows records from table in a sweep.
7566 */
7567
7568 10062808 static void get_sort_and_sweep_cost(TABLE *table, ha_rows nrows,
7569 Cost_estimate *cost) {
7570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10062808 times.
10062808 assert(cost->is_zero());
7571
2/2
✓ Branch 0 taken 10062794 times.
✓ Branch 1 taken 14 times.
10062808 if (nrows) {
7572 10062794 get_sweep_read_cost(table, nrows, false, cost);
7573
7574 /*
7575 @todo CostModel: For the old version of the cost model the
7576 following code should be used. For the new version of the cost
7577 model Cost_model::key_compare_cost() should be used. When
7578 removing support for the old cost model this code should be
7579 removed. The reason for this is that we should get rid of the
7580 ROWID_COMPARE_SORT_COST and use key_compare_cost() instead. For
7581 the current value returned by key_compare_cost() this would
7582 overestimate the cost for sorting.
7583 */
7584
7585 /*
7586 Constant for the cost of doing one key compare operation in the
7587 sort operation. We should have used the value returned by
7588 key_compare_cost() here but this would make the cost
7589 estimate of sorting very high for queries accessing many
7590 records. Until this constant is adjusted we introduce a constant
7591 that is more realistic. @todo: Replace this with
7592 key_compare_cost() when this has been given a realistic value.
7593 */
7594 const double ROWID_COMPARE_SORT_COST =
7595 10062794 table->cost_model()->key_compare_cost(1.0) / 10;
7596
7597 /* Add cost of qsort call: n * log2(n) * cost(rowid_comparison) */
7598
7599 // For the old version of the cost model this cost calculations should
7600 // be used....
7601 10062794 const double cpu_sort = nrows * log2(nrows) * ROWID_COMPARE_SORT_COST;
7602 // .... For the new cost model something like this should be used...
7603 // cpu_sort= nrows * log2(nrows) *
7604 // table->cost_model()->rowid_compare_cost();
7605 10062794 cost->add_cpu(cpu_sort);
7606 }
7607 10062808 }
7608
7609 /**
7610 Get cost of reading nrows table records in a "disk sweep"
7611
7612 A disk sweep read is a sequence of handler->rnd_pos(rowid) calls that made
7613 for an ordered sequence of rowids.
7614
7615 We take into account that some of the records might be in a memory
7616 buffer while others need to be read from a secondary storage
7617 device. The model for this assumes hard disk IO. A disk read is
7618 performed as follows:
7619
7620 1. The disk head is moved to the needed cylinder
7621 2. The controller waits for the plate to rotate
7622 3. The data is transferred
7623
7624 Time to do #3 is insignificant compared to #2+#1.
7625
7626 Time to move the disk head is proportional to head travel distance.
7627
7628 Time to wait for the plate to rotate depends on whether the disk head
7629 was moved or not.
7630
7631 If disk head wasn't moved, the wait time is proportional to distance
7632 between the previous block and the block we're reading.
7633
7634 If the head was moved, we don't know how much we'll need to wait for the
7635 plate to rotate. We assume the wait time to be a variate with a mean of
7636 0.5 of full rotation time.
7637
7638 Our cost units are "random disk seeks". The cost of random disk seek is
7639 actually not a constant, it depends one range of cylinders we're going
7640 to access. We make it constant by introducing a fuzzy concept of "typical
7641 datafile length" (it's fuzzy as it's hard to tell whether it should
7642 include index file, temp.tables etc). Then random seek cost is:
7643
7644 1 = half_rotation_cost + move_cost * 1/3 * typical_data_file_length
7645
7646 We define half_rotation_cost as disk_seek_base_cost() (see
7647 Cost_model_server::disk_seek_base_cost()).
7648
7649 @param table Table to be accessed
7650 @param nrows Number of rows to retrieve
7651 @param interrupted true <=> Assume that the disk sweep will be
7652 interrupted by other disk IO. false - otherwise.
7653 @param[out] cost the cost
7654 */
7655
7656 10163923 void get_sweep_read_cost(TABLE *table, ha_rows nrows, bool interrupted,
7657 Cost_estimate *cost) {
7658
1/2
✓ Branch 0 taken 10163923 times.
✗ Branch 1 not taken.
10163923 DBUG_TRACE;
7659
7660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10163923 times.
10163923 assert(cost->is_zero());
7661
2/2
✓ Branch 0 taken 10163786 times.
✓ Branch 1 taken 137 times.
10163923 if (nrows > 0) {
7662 10163786 const Cost_model_table *const cost_model = table->cost_model();
7663
7664 // The total number of blocks used by this table
7665 double n_blocks =
7666 10163786 ceil(ulonglong2double(table->file->stats.data_file_length) / IO_SIZE);
7667
2/2
✓ Branch 0 taken 10030020 times.
✓ Branch 1 taken 133766 times.
10163786 if (n_blocks < 1.0) // When data_file_length is 0
7668 10030020 n_blocks = 1.0;
7669
7670 /*
7671 The number of blocks that in average need to be read given that
7672 the records are uniformly distribution over the table.
7673 */
7674 double busy_blocks =
7675 10163786 n_blocks * (1.0 - pow(1.0 - 1.0 / n_blocks, rows2double(nrows)));
7676
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 10163765 times.
10163786 if (busy_blocks < 1.0) busy_blocks = 1.0;
7677
7678
3/8
✓ Branch 0 taken 10163786 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10163786 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10163786 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10163786 DBUG_PRINT("info",
7679 ("sweep: nblocks=%g, busy_blocks=%g", n_blocks, busy_blocks));
7680 /*
7681 The random access cost for reading the data pages will be the upper
7682 limit for the sweep_cost.
7683 */
7684
1/2
✓ Branch 0 taken 10163786 times.
✗ Branch 1 not taken.
10163786 cost->add_io(cost_model->page_read_cost(busy_blocks));
7685
2/2
✓ Branch 0 taken 10064164 times.
✓ Branch 1 taken 99622 times.
10163786 if (!interrupted) {
7686 10064164 Cost_estimate sweep_cost;
7687 /*
7688 Assume reading pages from disk is done in one 'sweep'.
7689
7690 The cost model and cost estimate for pages already in a memory
7691 buffer will be different from pages that needed to be read from
7692 disk. Calculate the number of blocks that likely already are
7693 in memory and the number of blocks that need to be read from
7694 disk.
7695 */
7696 const double busy_blocks_mem =
7697
1/2
✓ Branch 0 taken 10064164 times.
✗ Branch 1 not taken.
10064164 busy_blocks * table->file->table_in_memory_estimate();
7698 10064164 const double busy_blocks_disk = busy_blocks - busy_blocks_mem;
7699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10064164 times.
10064164 assert(busy_blocks_disk >= 0.0);
7700
7701 // Cost of accessing blocks in main memory buffer
7702 10064164 sweep_cost.add_io(cost_model->buffer_block_read_cost(busy_blocks_mem));
7703
7704 // Cost of reading blocks from disk in a 'sweep'
7705 10064164 const double seek_distance =
7706
2/2
✓ Branch 0 taken 608 times.
✓ Branch 1 taken 10063556 times.
10064164 (busy_blocks_disk > 1.0) ? n_blocks / busy_blocks_disk : n_blocks;
7707
7708 const double disk_cost =
7709 10064164 busy_blocks_disk * cost_model->disk_seek_cost(seek_distance);
7710 10064164 sweep_cost.add_io(disk_cost);
7711
7712 /*
7713 For some cases, ex: when only few blocks need to be read and the
7714 seek distance becomes very large, the sweep cost model can produce
7715 a cost estimate that is larger than the cost of random access.
7716 To handle this case, we use the sweep cost only when it is less
7717 than the random access cost.
7718 */
7719
2/2
✓ Branch 0 taken 485 times.
✓ Branch 1 taken 10063679 times.
10064164 if (sweep_cost < *cost) *cost = sweep_cost;
7720 }
7721 }
7722
3/8
✓ Branch 0 taken 10163923 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10163923 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10163923 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10163923 DBUG_PRINT("info", ("returning cost=%g", cost->total_cost()));
7723 10163923 }
7724
7725 /****************************************************************************
7726 * DS-MRR implementation ends
7727 ***************************************************************************/
7728
7729 /** @brief
7730 Read first row between two ranges.
7731 Store ranges for future calls to read_range_next.
7732
7733 @param start_key Start key. Is 0 if no min range
7734 @param end_key End key. Is 0 if no max range
7735 @param eq_range_arg Set to 1 if start_key == end_key
7736 @param sorted Set to 1 if result should be sorted per key
7737
7738 @note
7739 Record is read into table->record[0]
7740
7741 @retval
7742 0 Found row
7743 @retval
7744 HA_ERR_END_OF_FILE No rows in range
7745 */
7746 10560278 int handler::read_range_first(const key_range *start_key,
7747 const key_range *end_key, bool eq_range_arg,
7748 bool sorted [[maybe_unused]]) {
7749 int result;
7750
1/2
✓ Branch 0 taken 10560449 times.
✗ Branch 1 not taken.
10560278 DBUG_TRACE;
7751
7752 10560449 eq_range = eq_range_arg;
7753
1/2
✓ Branch 0 taken 10560402 times.
✗ Branch 1 not taken.
10560449 set_end_range(end_key, RANGE_SCAN_ASC);
7754
7755 10560402 range_key_part = table->key_info[active_index].key_part;
7756
7757
2/2
✓ Branch 0 taken 4631 times.
✓ Branch 1 taken 10555771 times.
10560402 if (!start_key) // Read first record
7758
1/2
✓ Branch 0 taken 4631 times.
✗ Branch 1 not taken.
4631 result = ha_index_first(table->record[0]);
7759 else
7760 10555856 result = ha_index_read_map(table->record[0], start_key->key,
7761
1/2
✓ Branch 0 taken 10555856 times.
✗ Branch 1 not taken.
10555771 start_key->keypart_map, start_key->flag);
7762
2/2
✓ Branch 0 taken 10229863 times.
✓ Branch 1 taken 330624 times.
10560487 if (result)
7763
2/2
✓ Branch 0 taken 2747 times.
✓ Branch 1 taken 10227116 times.
10229863 return (result == HA_ERR_KEY_NOT_FOUND) ? HA_ERR_END_OF_FILE : result;
7764
7765
3/4
✓ Branch 0 taken 330624 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9765 times.
✓ Branch 3 taken 320859 times.
330624 if (compare_key(end_range) > 0) {
7766 /*
7767 The last read row does not fall in the range. So request
7768 storage engine to release row lock if possible.
7769 */
7770
1/2
✓ Branch 0 taken 9765 times.
✗ Branch 1 not taken.
9765 unlock_row();
7771 9765 result = HA_ERR_END_OF_FILE;
7772 }
7773 330624 return result;
7774 10560487 }
7775
7776 24526 int handler::ha_read_range_first(const key_range *start_key,
7777 const key_range *end_key, bool eq_range,
7778 bool sorted) {
7779 int result;
7780
1/2
✓ Branch 0 taken 24526 times.
✗ Branch 1 not taken.
24526 DBUG_TRACE;
7781
7782 // Set status for the need to update generated fields
7783 24526 m_update_generated_read_fields = table->has_gcol();
7784
7785
1/2
✓ Branch 0 taken 24526 times.
✗ Branch 1 not taken.
24526 result = read_range_first(start_key, end_key, eq_range, sorted);
7786
3/4
✓ Branch 0 taken 9003 times.
✓ Branch 1 taken 15523 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9003 times.
24526 if (!result && m_update_generated_read_fields) {
7787 result =
7788 update_generated_read_fields(table->record[0], table, active_index);
7789 m_update_generated_read_fields = false;
7790 }
7791 24526 table->set_row_status_from_handler(result);
7792 24526 return result;
7793 24526 }
7794
7795 56209 int handler::ha_read_range_next() {
7796 int result;
7797
1/2
✓ Branch 0 taken 56209 times.
✗ Branch 1 not taken.
56209 DBUG_TRACE;
7798
7799 // Set status for the need to update generated fields
7800 56209 m_update_generated_read_fields = table->has_gcol();
7801
7802
1/2
✓ Branch 0 taken 56209 times.
✗ Branch 1 not taken.
56209 result = read_range_next();
7803
3/4
✓ Branch 0 taken 47531 times.
✓ Branch 1 taken 8678 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 47531 times.
56209 if (!result && m_update_generated_read_fields) {
7804 result =
7805 update_generated_read_fields(table->record[0], table, active_index);
7806 m_update_generated_read_fields = false;
7807 }
7808 56209 table->set_row_status_from_handler(result);
7809 56209 return result;
7810 56209 }
7811
7812 /** @brief
7813 Read next row between two endpoints.
7814
7815 @note
7816 Record is read into table->record[0]
7817
7818 @retval
7819 0 Found row
7820 @retval
7821 HA_ERR_END_OF_FILE No rows in range
7822 */
7823 3358087 int handler::read_range_next() {
7824
1/2
✓ Branch 0 taken 3358087 times.
✗ Branch 1 not taken.
3358087 DBUG_TRACE;
7825
7826 int result;
7827
2/2
✓ Branch 0 taken 618558 times.
✓ Branch 1 taken 2739529 times.
3358087 if (eq_range) {
7828 /* We trust that index_next_same always gives a row in range */
7829 result =
7830
1/2
✓ Branch 0 taken 618558 times.
✗ Branch 1 not taken.
618558 ha_index_next_same(table->record[0], end_range->key, end_range->length);
7831 } else {
7832
1/2
✓ Branch 0 taken 2739529 times.
✗ Branch 1 not taken.
2739529 result = ha_index_next(table->record[0]);
7833
2/2
✓ Branch 0 taken 8716 times.
✓ Branch 1 taken 2730813 times.
2739529 if (result) return result;
7834
7835
3/4
✓ Branch 0 taken 2730813 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6154 times.
✓ Branch 3 taken 2724659 times.
2730813 if (compare_key(end_range) > 0) {
7836 /*
7837 The last read row does not fall in the range. So request
7838 storage engine to release row lock if possible.
7839 */
7840
1/2
✓ Branch 0 taken 6154 times.
✗ Branch 1 not taken.
6154 unlock_row();
7841 6154 result = HA_ERR_END_OF_FILE;
7842 }
7843 }
7844 3349371 return result;
7845 3358087 }
7846
7847 /**
7848 Check if one of the columns in a key is a virtual generated column.
7849
7850 @param part the first part of the key to check
7851 @param length the length of the key
7852 @retval true if the key contains a virtual generated column
7853 @retval false if the key does not contain a virtual generated column
7854 */
7855 420632 static bool key_has_vcol(const KEY_PART_INFO *part, uint length) {
7856
2/2
✓ Branch 0 taken 501803 times.
✓ Branch 1 taken 420370 times.
922173 for (uint len = 0; len < length; len += part->store_length, ++part)
7857
2/2
✓ Branch 0 taken 253 times.
✓ Branch 1 taken 501541 times.
501803 if (part->field->is_virtual_gcol()) return true;
7858 420370 return false;
7859 }
7860
7861 10616870 void handler::set_end_range(const key_range *range,
7862 enum_range_scan_direction direction) {
7863
2/2
✓ Branch 0 taken 420625 times.
✓ Branch 1 taken 10196245 times.
10616870 if (range) {
7864 420625 save_end_range = *range;
7865 420625 end_range = &save_end_range;
7866 420625 range_key_part = table->key_info[active_index].key_part;
7867 420625 key_compare_result_on_equal =
7868 420625 (range->flag == HA_READ_BEFORE_KEY)
7869
2/2
✓ Branch 0 taken 413257 times.
✓ Branch 1 taken 7368 times.
833882 ? 1
7870
2/2
✓ Branch 0 taken 413172 times.
✓ Branch 1 taken 85 times.
413257 : (range->flag == HA_READ_AFTER_KEY ? -1 : 0);
7871 420625 m_virt_gcol_in_end_range = key_has_vcol(range_key_part, range->length);
7872 } else
7873 10196245 end_range = nullptr;
7874
7875 /*
7876 Clear the out-of-range flag in the record buffer when a new range is
7877 started. Also set the in_range_check_pushed_down flag, since the
7878 storage engine needs to do the evaluation of the end-range to avoid
7879 filling the record buffer with out-of-range records.
7880 */
7881
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 10616802 times.
10616898 if (m_record_buffer != nullptr) {
7882 96 m_record_buffer->set_out_of_range(false);
7883 96 in_range_check_pushed_down = true;
7884 }
7885
7886 10616898 range_scan_direction = direction;
7887 10616898 }
7888
7889 /**
7890 Compare if found key (in row) is over max-value.
7891
7892 @param range range to compare to row. May be 0 for no range
7893
7894 @sa
7895 key.cc::key_cmp()
7896
7897 @return
7898 The return value is SIGN(key_in_row - range_key):
7899
7900 - 0 : Key is equal to range or 'range' == 0 (no range)
7901 - -1 : Key is less than range
7902 - 1 : Key is larger than range
7903 */
7904 3105351 int handler::compare_key(key_range *range) {
7905 int cmp;
7906
4/4
✓ Branch 0 taken 1153398 times.
✓ Branch 1 taken 1951953 times.
✓ Branch 2 taken 5824 times.
✓ Branch 3 taken 1147574 times.
3105351 if (!range || in_range_check_pushed_down) return 0; // No max range
7907 1147574 cmp = key_cmp(range_key_part, range->key, range->length);
7908
2/2
✓ Branch 0 taken 366446 times.
✓ Branch 1 taken 781128 times.
1147574 if (!cmp) cmp = key_compare_result_on_equal;
7909 1147574 return cmp;
7910 }
7911
7912 /*
7913 Compare if a found key (in row) is within the range.
7914
7915 This function is similar to compare_key() but checks the range scan
7916 direction to determine if this is a descending scan. This function
7917 is used by the index condition pushdown implementation to determine
7918 if the read record is within the range scan.
7919
7920 @param range Range to compare to row. May be NULL for no range.
7921
7922 @seealso
7923 handler::compare_key()
7924
7925 @return Returns whether the key is within the range
7926
7927 - 0 : Key is equal to range or 'range' == 0 (no range)
7928 - -1 : Key is within the current range
7929 - 1 : Key is outside the current range
7930 */
7931
7932 9356 int handler::compare_key_icp(const key_range *range) const {
7933 int cmp;
7934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9356 times.
9356 if (!range) return 0; // no max range
7935 9356 cmp = key_cmp(range_key_part, range->key, range->length);
7936
2/2
✓ Branch 0 taken 2542 times.
✓ Branch 1 taken 6814 times.
9356 if (!cmp) cmp = key_compare_result_on_equal;
7937
2/2
✓ Branch 0 taken 688 times.
✓ Branch 1 taken 8668 times.
9356 if (range_scan_direction == RANGE_SCAN_DESC) cmp = -cmp;
7938 9356 return cmp;
7939 }
7940
7941 /**
7942 Change the offsets of all the fields in a key range.
7943
7944 @param range the key range
7945 @param key_part the first key part
7946 @param diff how much to change the offsets with
7947 */
7948 6 static inline void move_key_field_offsets(const key_range *range,
7949 const KEY_PART_INFO *key_part,
7950 ptrdiff_t diff) {
7951
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (size_t len = 0; len < range->length;
7952 6 len += key_part->store_length, ++key_part)
7953 6 key_part->field->move_field_offset(diff);
7954 6 }
7955
7956 /**
7957 Check if the key in the given buffer (which is not necessarily
7958 TABLE::record[0]) is within range. Called by the storage engine to
7959 avoid reading too many rows.
7960
7961 @param buf the buffer that holds the key
7962 @retval -1 if the key is within the range
7963 @retval 0 if the key is equal to the end_range key, and
7964 key_compare_result_on_equal is 0
7965 @retval 1 if the key is outside the range
7966 */
7967 3 int handler::compare_key_in_buffer(const uchar *buf) const {
7968
2/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 assert(end_range != nullptr &&
7969 (m_record_buffer == nullptr || !m_record_buffer->is_out_of_range()));
7970
7971 // Make the fields in the key point into the buffer instead of record[0].
7972 3 const ptrdiff_t diff = buf - table->record[0];
7973
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (diff != 0) move_key_field_offsets(end_range, range_key_part, diff);
7974
7975 // Compare the key in buf against end_range.
7976 3 int cmp = key_cmp(range_key_part, end_range->key, end_range->length);
7977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (cmp == 0) cmp = key_compare_result_on_equal;
7978
7979 // Reset the field offsets.
7980
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (diff != 0) move_key_field_offsets(end_range, range_key_part, -diff);
7981
7982 // This change is necessary for MyRocks PS-7116.
7983
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (range_scan_direction == RANGE_SCAN_DESC) cmp = -cmp;
7984
7985 3 return cmp;
7986 }
7987
7988 50798696 int handler::index_read_idx_map(uchar *buf, uint index, const uchar *key,
7989 key_part_map keypart_map,
7990 enum ha_rkey_function find_flag) {
7991 50798696 int error, error1 = 0;
7992 50798696 error = index_init(index, false);
7993
1/2
✓ Branch 0 taken 50799279 times.
✗ Branch 1 not taken.
50799277 if (!error) {
7994 50799279 error = index_read_map(buf, key, keypart_map, find_flag);
7995 50799293 error1 = index_end();
7996 }
7997
2/2
✓ Branch 0 taken 17754516 times.
✓ Branch 1 taken 33044787 times.
50799303 return error ? error : error1;
7998 }
7999
8000 76103955 uint calculate_key_len(TABLE *table, uint key, key_part_map keypart_map,
8001 uint *count) {
8002 /* works only with key prefixes */
8003
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76103955 times.
76103955 assert(((keypart_map + 1) & keypart_map) == 0);
8004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76103955 times.
76103955 if (count) *count = 0;
8005
8006 76103955 KEY *key_info = table->key_info + key;
8007 76103955 KEY_PART_INFO *key_part = key_info->key_part;
8008 76103955 KEY_PART_INFO *end_key_part = key_part + actual_key_parts(key_info);
8009 76104407 uint length = 0;
8010
8011
4/4
✓ Branch 0 taken 130706931 times.
✓ Branch 1 taken 44671500 times.
✓ Branch 2 taken 99274024 times.
✓ Branch 3 taken 31432907 times.
175378431 while (key_part < end_key_part && keypart_map) {
8012 99274024 length += key_part->store_length;
8013 99274024 keypart_map >>= 1;
8014 99274024 key_part++;
8015 }
8016
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76104407 times.
76104407 if (count) *count = key_part - key_info->key_part;
8017
8018 76104407 return length;
8019 }
8020
8021 /**
8022 Returns a list of all known extensions.
8023
8024 No mutexes, worst case race is a minor surplus memory allocation
8025 We have to recreate the extension map if mysqld is restarted (for example
8026 within libmysqld)
8027
8028 @retval
8029 pointer pointer to TYPELIB structure
8030 */
8031 55449 static bool exts_handlerton(THD *, plugin_ref plugin, void *arg) {
8032 55449 List<const char> *found_exts = static_cast<List<const char> *>(arg);
8033 55449 handlerton *hton = plugin_data<handlerton *>(plugin);
8034
4/4
✓ Branch 0 taken 55426 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 25347 times.
✓ Branch 3 taken 30079 times.
55449 if (hton->state == SHOW_OPTION_YES && hton->file_extensions) {
8035
1/2
✓ Branch 0 taken 25347 times.
✗ Branch 1 not taken.
25347 List_iterator_fast<const char> it(*found_exts);
8036 const char **ext, *old_ext;
8037
8038
2/2
✓ Branch 0 taken 35565 times.
✓ Branch 1 taken 25347 times.
60912 for (ext = hton->file_extensions; *ext; ext++) {
8039
2/2
✓ Branch 0 taken 106200 times.
✓ Branch 1 taken 35565 times.
141765 while ((old_ext = it++)) {
8040
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106200 times.
106200 if (!strcmp(old_ext, *ext)) break;
8041 }
8042
2/4
✓ Branch 0 taken 35565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 35565 times.
✗ Branch 3 not taken.
35565 if (!old_ext) found_exts->push_back(*ext);
8043
8044 35565 it.rewind();
8045 }
8046 }
8047 55449 return false;
8048 }
8049
8050 5109 TYPELIB *ha_known_exts() {
8051
2/4
✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5109 times.
✗ Branch 3 not taken.
5109 TYPELIB *known_extensions = (TYPELIB *)(*THR_MALLOC)->Alloc(sizeof(TYPELIB));
8052 5109 known_extensions->name = "known_exts";
8053 5109 known_extensions->type_lengths = nullptr;
8054
8055 5109 List<const char> found_exts;
8056 const char **ext, *old_ext;
8057
8058
1/2
✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
5109 plugin_foreach(nullptr, exts_handlerton, MYSQL_STORAGE_ENGINE_PLUGIN,
8059 &found_exts);
8060
8061 5109 size_t arr_length = sizeof(char *) * (found_exts.elements + 1);
8062
2/4
✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5109 times.
✗ Branch 3 not taken.
5109 ext = (const char **)(*THR_MALLOC)->Alloc(arr_length);
8063
8064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5109 times.
5109 assert(nullptr != ext);
8065 5109 known_extensions->count = found_exts.elements;
8066 5109 known_extensions->type_names = ext;
8067
8068
1/2
✓ Branch 0 taken 5109 times.
✗ Branch 1 not taken.
5109 List_iterator_fast<const char> it(found_exts);
8069
2/2
✓ Branch 0 taken 35565 times.
✓ Branch 1 taken 5109 times.
40674 while ((old_ext = it++)) *ext++ = old_ext;
8070 5109 *ext = nullptr;
8071 5109 return known_extensions;
8072 }
8073
8074 12727 static bool stat_print(THD *thd, const char *type, size_t type_len,
8075 const char *file, size_t file_len, const char *status,
8076 size_t status_len) {
8077 12727 Protocol *protocol = thd->get_protocol();
8078 12727 protocol->start_row();
8079 12727 protocol->store_string(type, type_len, system_charset_info);
8080 12727 protocol->store_string(file, file_len, system_charset_info);
8081 12727 protocol->store_string(status, status_len, system_charset_info);
8082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12727 times.
12727 if (protocol->end_row()) return true;
8083 12727 return false;
8084 }
8085
8086 33 static bool showstat_handlerton(THD *thd, plugin_ref plugin, void *arg) {
8087 33 enum ha_stat_type stat = *(enum ha_stat_type *)arg;
8088 33 handlerton *hton = plugin_data<handlerton *>(plugin);
8089
4/6
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 27 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 times.
39 if (hton->state == SHOW_OPTION_YES && hton->show_status &&
8090
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 hton->show_status(hton, thd, stat_print, stat))
8091 return true;
8092 33 return false;
8093 }
8094
8095 340 bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat) {
8096 340 mem_root_deque<Item *> field_list(thd->mem_root);
8097
3/6
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
340 field_list.push_back(new Item_empty_string("Type", 10));
8098
3/6
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
340 field_list.push_back(new Item_empty_string("Name", FN_REFLEN));
8099
3/6
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
340 field_list.push_back(new Item_empty_string("Status", 10));
8100
8101
2/4
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 340 times.
340 if (thd->send_result_metadata(field_list,
8102 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
8103 return true;
8104
8105 bool result;
8106
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 337 times.
340 if (db_type == nullptr) {
8107
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 result = plugin_foreach(thd, showstat_handlerton,
8108 MYSQL_STORAGE_ENGINE_PLUGIN, &stat);
8109 } else {
8110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 337 times.
337 if (db_type->state != SHOW_OPTION_YES) {
8111 const LEX_CSTRING *name = &se_plugin_array[db_type->slot]->name;
8112 result = stat_print(thd, name->str, name->length, "", 0, "DISABLED", 8)
8113 ? true
8114 : false;
8115 } else {
8116
2/6
✓ Branch 0 taken 337 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 337 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
337 DBUG_EXECUTE_IF("simulate_show_status_failure",
8117 DBUG_SET("+d,simulate_net_write_failure"););
8118 674 result = db_type->show_status &&
8119
1/2
✓ Branch 0 taken 331 times.
✗ Branch 1 not taken.
331 db_type->show_status(db_type, thd, stat_print, stat)
8120
3/4
✓ Branch 0 taken 331 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 331 times.
668 ? true
8121 : false;
8122
2/6
✓ Branch 0 taken 337 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 337 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
337 DBUG_EXECUTE_IF("simulate_show_status_failure",
8123 DBUG_SET("-d,simulate_net_write_failure"););
8124 }
8125 }
8126
8127
2/4
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 340 times.
✗ Branch 3 not taken.
340 if (!result) my_eof(thd);
8128 340 return result;
8129 340 }
8130
8131 /*
8132 Function to check if the conditions for row-based binlogging is
8133 correct for the table.
8134
8135 A row in the given table should be replicated if:
8136 - Row-based replication is enabled in the current thread
8137 - The binlog is enabled
8138 - It is not a temporary table
8139 - The binary log is open
8140 - The database the table resides in shall be binlogged (binlog_*_db rules)
8141 - table is not mysql.event
8142 */
8143
8144 174314708 static bool check_table_binlog_row_based(THD *thd, TABLE *table) {
8145
2/2
✓ Branch 0 taken 802222 times.
✓ Branch 1 taken 173512486 times.
174314708 if (table->s->cached_row_logging_check == -1) {
8146 1108753 int const check(table->s->tmp_table == NO_TMP_TABLE &&
8147
4/4
✓ Branch 0 taken 306531 times.
✓ Branch 1 taken 495691 times.
✓ Branch 2 taken 284940 times.
✓ Branch 3 taken 21591 times.
1087162 !table->no_replicate &&
8148
2/2
✓ Branch 0 taken 284801 times.
✓ Branch 1 taken 139 times.
284940 binlog_filter->db_ok(table->s->db.str));
8149 802222 table->s->cached_row_logging_check = check;
8150 }
8151
8152
3/4
✓ Branch 0 taken 84238628 times.
✓ Branch 1 taken 90076080 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84238628 times.
174314708 assert(table->s->cached_row_logging_check == 0 ||
8153 table->s->cached_row_logging_check == 1);
8154
8155 #ifdef WITH_WSREP
8156 /*
8157 In addition to above conditions, PXC allows replication if:
8158 1. Binlogging was not disabled internally by the server with the
8159 explicit intention to not replicate (OPTION_BIN_LOG_INTERNAL_OFF flag)
8160 2a. We are in binlog emulation mode and current thread is not applier thread
8161 2b. PXC replication for current is enabled (wsrep_on == true)
8162 */
8163 174314708 return (thd->is_current_stmt_binlog_format_row() &&
8164
2/2
✓ Branch 0 taken 63767327 times.
✓ Branch 1 taken 83365846 times.
147133173 table->s->cached_row_logging_check &&
8165
6/6
✓ Branch 0 taken 147133173 times.
✓ Branch 1 taken 27181902 times.
✓ Branch 2 taken 59246271 times.
✓ Branch 3 taken 4521056 times.
✓ Branch 4 taken 59246258 times.
✓ Branch 5 taken 13 times.
380694302 !(thd->variables.option_bits & OPTION_BIN_LOG_INTERNAL_OFF) &&
8166
11/12
✓ Branch 0 taken 13583750 times.
✓ Branch 1 taken 45662508 times.
✓ Branch 2 taken 13045304 times.
✓ Branch 3 taken 538446 times.
✓ Branch 4 taken 13045298 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 190223 times.
✓ Branch 7 taken 12855075 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 190220 times.
✓ Branch 10 taken 59056051 times.
✗ Branch 11 not taken.
59246271 (((WSREP_EMULATE_BINLOG(thd) && (!wsrep_thd_is_applying(thd))) ||
8167
10/10
✓ Branch 0 taken 13393527 times.
✓ Branch 1 taken 45662524 times.
✓ Branch 2 taken 12855081 times.
✓ Branch 3 taken 538446 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 12855075 times.
✓ Branch 6 taken 46139200 times.
✓ Branch 7 taken 61776 times.
✓ Branch 8 taken 58252434 times.
✓ Branch 9 taken 741624 times.
118050109 (((WSREP(thd) || thd->variables.option_bits & OPTION_BIN_LOG)) &&
8168 233309133 mysql_bin_log.is_open()))));
8169 #else
8170 return (thd->is_current_stmt_binlog_format_row() &&
8171 table->s->cached_row_logging_check &&
8172 (thd->variables.option_bits & OPTION_BIN_LOG) &&
8173 mysql_bin_log.is_open());
8174 #endif
8175 }
8176
8177 /** @brief
8178 Write table maps for all (manually or automatically) locked tables
8179 to the binary log.
8180
8181 SYNOPSIS
8182 write_locked_table_maps()
8183 thd Pointer to THD structure
8184
8185 DESCRIPTION
8186 This function will generate and write table maps for all tables
8187 that are locked by the thread 'thd'.
8188
8189 RETURN VALUE
8190 0 All OK
8191 1 Failed to write all table maps
8192
8193 SEE ALSO
8194 THD::lock
8195 */
8196
8197 47727136 static int write_locked_table_maps(THD *thd) {
8198
1/2
✓ Branch 0 taken 47727182 times.
✗ Branch 1 not taken.
47727136 DBUG_TRACE;
8199
5/8
✓ Branch 0 taken 47727160 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47727156 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 47727110 times.
✓ Branch 6 taken 46 times.
✗ Branch 7 not taken.
47727182 DBUG_PRINT("enter", ("thd: %p thd->lock: %p "
8200 "thd->extra_lock: %p",
8201 thd, thd->lock, thd->extra_lock));
8202
8203
5/8
✓ Branch 0 taken 47727080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47727124 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 47727078 times.
✓ Branch 6 taken 46 times.
✗ Branch 7 not taken.
47727156 DBUG_PRINT("debug",
8204 ("get_binlog_table_maps(): %d", thd->get_binlog_table_maps()));
8205
8206
2/2
✓ Branch 0 taken 4233325 times.
✓ Branch 1 taken 43493779 times.
47727124 if (thd->get_binlog_table_maps() == 0) {
8207
2/2
✓ Branch 0 taken 8466138 times.
✓ Branch 1 taken 4233072 times.
12699473 for (MYSQL_LOCK *lock : {thd->extra_lock, thd->lock}) {
8208
2/2
✓ Branch 0 taken 4229211 times.
✓ Branch 1 taken 4236927 times.
8466138 if (lock == nullptr) continue;
8209
8210 4236927 bool need_binlog_rows_query = thd->variables.binlog_rows_query_log_events;
8211 4236927 TABLE **const end_ptr = lock->table + lock->table_count;
8212
2/2
✓ Branch 0 taken 4404574 times.
✓ Branch 1 taken 4236937 times.
8641511 for (TABLE **table_ptr = lock->table; table_ptr != end_ptr; ++table_ptr) {
8213 4404574 TABLE *const table = *table_ptr;
8214
5/8
✓ Branch 0 taken 4404590 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4404580 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 4404549 times.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
4404574 DBUG_PRINT("info", ("Checking table %s", table->s->table_name.str));
8215
4/4
✓ Branch 0 taken 4247148 times.
✓ Branch 1 taken 157438 times.
✓ Branch 2 taken 4247147 times.
✓ Branch 3 taken 157459 times.
8651754 if (table->current_lock == F_WRLCK &&
8216
3/4
✓ Branch 0 taken 4247168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4247158 times.
✓ Branch 3 taken 10 times.
4247148 check_table_binlog_row_based(thd, table)) {
8217 /*
8218 We need to have a transactional behavior for SQLCOM_CREATE_TABLE
8219 (e.g. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
8220 compatible behavior with the STMT based replication even when
8221 the table is not transactional. In other words, if the operation
8222 fails while executing the insert phase nothing is written to the
8223 binlog.
8224
8225 Note that at this point, we check the type of a set of tables to
8226 create the table map events. In the function binlog_log_row(),
8227 which calls the current function, we check the type of the table
8228 of the current row.
8229 */
8230
4/4
✓ Branch 0 taken 4239749 times.
✓ Branch 1 taken 7398 times.
✓ Branch 2 taken 3909301 times.
✓ Branch 3 taken 330431 times.
8486879 bool const has_trans = thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
8231 4239749 table->file->has_transactions();
8232
1/2
✓ Branch 0 taken 4247153 times.
✗ Branch 1 not taken.
4247130 int const error = thd->binlog_write_table_map(table, has_trans,
8233 need_binlog_rows_query);
8234 /* Binlog Rows_query log event once for one statement which updates
8235 two or more tables.*/
8236
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 4247076 times.
4247153 if (need_binlog_rows_query) need_binlog_rows_query = false;
8237 /*
8238 If an error occurs, it is the responsibility of the caller to
8239 roll back the transaction.
8240 */
8241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4247125 times.
4247153 if (unlikely(error)) return 1;
8242 }
8243 }
8244 }
8245 }
8246 47726851 return 0;
8247 47726851 }
8248
8249 /**
8250 The purpose of an instance of this class is to :
8251
8252 1) Given a TABLE instance, backup the given TABLE::read_set, TABLE::write_set
8253 and restore those members upon this instance disposal.
8254
8255 2) Store a reference to a dynamically allocated buffer and dispose of it upon
8256 this instance disposal.
8257 */
8258
8259 class Binlog_log_row_cleanup {
8260 public:
8261 /**
8262 This constructor aims to create temporary copies of readset and writeset.
8263
8264 @param table A pointer to TABLE object
8265 @param temp_read_bitmap Temporary BITMAP to store read_set.
8266 @param temp_write_bitmap Temporary BITMAP to store write_set.
8267 */
8268 47727035 Binlog_log_row_cleanup(TABLE &table, MY_BITMAP &temp_read_bitmap,
8269
8270 MY_BITMAP &temp_write_bitmap)
8271
8272 47727035 : m_cleanup_table(table),
8273 47727035 m_cleanup_read_bitmap(temp_read_bitmap),
8274 47727035 m_cleanup_write_bitmap(temp_write_bitmap) {
8275 47727035 bitmap_copy(&this->m_cleanup_read_bitmap, this->m_cleanup_table.read_set);
8276 47727196 bitmap_copy(&this->m_cleanup_write_bitmap, this->m_cleanup_table.write_set);
8277 47727215 }
8278
8279 /**
8280 This destructor aims to restore the original readset and writeset and
8281 delete the temporary copies.
8282 */
8283 95454128 virtual ~Binlog_log_row_cleanup() {
8284 95454128 bitmap_copy(this->m_cleanup_table.read_set, &this->m_cleanup_read_bitmap);
8285 95454400 bitmap_copy(this->m_cleanup_table.write_set, &this->m_cleanup_write_bitmap);
8286 95454426 bitmap_free(&this->m_cleanup_read_bitmap);
8287 95454442 bitmap_free(&this->m_cleanup_write_bitmap);
8288 }
8289
8290 private:
8291 TABLE &m_cleanup_table; // Creating a TABLE to get access to its members.
8292 MY_BITMAP &m_cleanup_read_bitmap; // Temporary bitmap to store read_set.
8293 MY_BITMAP &m_cleanup_write_bitmap; // Temporary bitmap to store write_set.
8294 };
8295
8296 163152897 int binlog_log_row(TABLE *table, const uchar *before_record,
8297 const uchar *after_record, Log_func *log_func) {
8298 163152897 bool error = false;
8299 163152897 THD *const thd = table->in_use;
8300
8301
2/2
✓ Branch 0 taken 47727039 times.
✓ Branch 1 taken 115425900 times.
163152897 if (check_table_binlog_row_based(thd, table)) {
8302
1/2
✓ Branch 0 taken 47727097 times.
✗ Branch 1 not taken.
47727039 if (thd->variables.transaction_write_set_extraction != HASH_ALGORITHM_OFF) {
8303 try {
8304 47727097 MY_BITMAP save_read_set;
8305 47727097 MY_BITMAP save_write_set;
8306
3/6
✓ Branch 0 taken 47727100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47727129 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 47727211 times.
95454337 if (bitmap_init(&save_read_set, nullptr, table->s->fields) ||
8307
2/4
✓ Branch 0 taken 47727240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47727241 times.
47727129 bitmap_init(&save_write_set, nullptr, table->s->fields)) {
8308 my_error(ER_OUT_OF_RESOURCES, MYF(0));
8309 return HA_ERR_RBR_LOGGING_FAILED;
8310 }
8311
8312 Binlog_log_row_cleanup cleanup_sentry(*table, save_read_set,
8313
1/2
✓ Branch 0 taken 47727192 times.
✗ Branch 1 not taken.
47727211 save_write_set);
8314
8315
2/2
✓ Branch 0 taken 15407 times.
✓ Branch 1 taken 47711785 times.
47727192 if (thd->variables.binlog_row_image == 0) {
8316
2/2
✓ Branch 0 taken 12596 times.
✓ Branch 1 taken 15407 times.
28003 for (uint key_number = 0; key_number < table->s->keys; ++key_number) {
8317
2/2
✓ Branch 0 taken 9438 times.
✓ Branch 1 taken 3158 times.
12596 if (((table->key_info[key_number].flags & (HA_NOSAME)) ==
8318 HA_NOSAME)) {
8319
1/2
✓ Branch 0 taken 9438 times.
✗ Branch 1 not taken.
9438 table->mark_columns_used_by_index_no_reset(key_number,
8320 table->read_set);
8321
1/2
✓ Branch 0 taken 9438 times.
✗ Branch 1 not taken.
9438 table->mark_columns_used_by_index_no_reset(key_number,
8322 table->write_set);
8323 }
8324 }
8325 }
8326 47727192 std::array<const uchar *, 2> records{after_record, before_record};
8327
2/2
✓ Branch 0 taken 95454003 times.
✓ Branch 1 taken 47727188 times.
143181485 for (auto rec : records) {
8328
2/2
✓ Branch 0 taken 51542387 times.
✓ Branch 1 taken 43911616 times.
95454003 if (rec != nullptr) {
8329
3/4
✓ Branch 0 taken 3815652 times.
✓ Branch 1 taken 47726735 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3815652 times.
51542387 assert(rec == table->record[0] || rec == table->record[1]);
8330
1/2
✓ Branch 0 taken 51542677 times.
✗ Branch 1 not taken.
51542387 bool res = add_pke(table, thd, rec);
8331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51542677 times.
51542677 if (res) return HA_ERR_RBR_LOGGING_FAILED;
8332 }
8333 }
8334
1/4
✓ Branch 0 taken 47727241 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
47727188 } catch (const std::bad_alloc &) {
8335 my_error(ER_OUT_OF_RESOURCES, MYF(0));
8336 return HA_ERR_RBR_LOGGING_FAILED;
8337 }
8338 }
8339
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 47727215 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
47727183 if (table->in_use->is_error()) return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
8340
8341 47727215 DBUG_DUMP("read_set 10", (uchar *)table->read_set->bitmap,
8342 (table->s->fields + 7) / 8);
8343
8344 /*
8345 If there are no table maps written to the binary log, this is
8346 the first row handled in this statement. In that case, we need
8347 to write table maps for all locked tables to the binary log.
8348 */
8349
2/2
✓ Branch 0 taken 47727219 times.
✓ Branch 1 taken 92 times.
47727183 if (likely(!(error = write_locked_table_maps(thd)))) {
8350 /*
8351 We need to have a transactional behavior for SQLCOM_CREATE_TABLE
8352 (i.e. CREATE TABLE... SELECT * FROM TABLE) in order to keep a
8353 compatible behavior with the STMT based replication even when
8354 the table is not transactional. In other words, if the operation
8355 fails while executing the insert phase nothing is written to the
8356 binlog.
8357 */
8358
4/4
✓ Branch 0 taken 45855902 times.
✓ Branch 1 taken 1871317 times.
✓ Branch 2 taken 42072310 times.
✓ Branch 3 taken 3783443 times.
93582972 bool const has_trans = thd->lex->sql_command == SQLCOM_CREATE_TABLE ||
8359 45855902 table->file->has_transactions();
8360 47727070 error = (*log_func)(thd, table, has_trans, before_record, after_record);
8361 }
8362 }
8363
8364
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 163152679 times.
163152687 return error ? HA_ERR_RBR_LOGGING_FAILED : 0;
8365 }
8366
8367 233049417 int handler::ha_external_lock(THD *thd, int lock_type) {
8368 int error;
8369
1/2
✓ Branch 0 taken 233052921 times.
✗ Branch 1 not taken.
233049417 DBUG_TRACE;
8370 /*
8371 Whether this is lock or unlock, this should be true, and is to verify that
8372 if get_auto_increment() was called (thus may have reserved intervals or
8373 taken a table lock), ha_release_auto_increment() was too.
8374 */
8375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 233052921 times.
233052921 assert(next_insert_id == 0);
8376 /* Consecutive calls for lock without unlocking in between is not allowed */
8377
6/8
✓ Branch 0 taken 232550482 times.
✓ Branch 1 taken 502439 times.
✓ Branch 2 taken 116276585 times.
✓ Branch 3 taken 116273897 times.
✓ Branch 4 taken 116276624 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 116273858 times.
233052921 assert(table_share->tmp_table != NO_TMP_TABLE ||
8378 ((lock_type != F_UNLCK && m_lock_type == F_UNLCK) ||
8379 lock_type == F_UNLCK));
8380 /* SQL HANDLER call locks/unlock while scanning (RND/INDEX). */
8381
3/4
✓ Branch 0 taken 708 times.
✓ Branch 1 taken 233052213 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 708 times.
233052921 assert(inited == NONE || table->open_by_handler);
8382
8383
1/2
✓ Branch 0 taken 233053103 times.
✗ Branch 1 not taken.
233052921 ha_statistic_increment(&System_status_var::ha_external_lock_count);
8384
8385
8/12
✓ Branch 0 taken 31141958 times.
✓ Branch 1 taken 201911145 times.
✓ Branch 2 taken 31140736 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31141315 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15560142 times.
✓ Branch 7 taken 15581173 times.
✓ Branch 8 taken 15560061 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 201911055 times.
✗ Branch 11 not taken.
233053103 MYSQL_TABLE_LOCK_WAIT(PSI_TABLE_EXTERNAL_LOCK, lock_type,
8386 { error = external_lock(thd, lock_type); })
8387
8388 /*
8389 We cache the table flags if the locking succeeded. Otherwise, we
8390 keep them as they were when they were fetched in ha_open().
8391 */
8392
8393
2/2
✓ Branch 0 taken 233051555 times.
✓ Branch 1 taken 734 times.
233052289 if (error == 0) {
8394 /*
8395 The lock type is needed by MRR when creating a clone of this handler
8396 object.
8397 */
8398 233051555 m_lock_type = lock_type;
8399
1/2
✓ Branch 0 taken 233050689 times.
✗ Branch 1 not taken.
233051555 cached_table_flags = table_flags();
8400 }
8401
8402 233051988 return error;
8403 233051423 }
8404
8405 /** @brief
8406 Check handler usage and reset state of file to after 'open'
8407
8408 @note can be called regardless of it is locked or not.
8409 */
8410 108793181 int handler::ha_reset() {
8411
1/2
✓ Branch 0 taken 108794444 times.
✗ Branch 1 not taken.
108793181 DBUG_TRACE;
8412 /* Check that we have called all proper deallocation functions */
8413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108794444 times.
108794444 assert((uchar *)table->def_read_set.bitmap + table->s->column_bitmap_size ==
8414 (uchar *)table->def_write_set.bitmap);
8415
2/4
✓ Branch 0 taken 108793986 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108793986 times.
108794444 assert(bitmap_is_set_all(&table->s->all_set));
8416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108793986 times.
108793986 assert(table->key_read == 0);
8417 /* ensure that ha_index_end / ha_rnd_end has been called */
8418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108793986 times.
108793986 assert(inited == NONE);
8419 /* Free cache used by filesort */
8420
1/2
✓ Branch 0 taken 108793344 times.
✗ Branch 1 not taken.
108793986 free_io_cache(table);
8421 /* reset the bitmaps to point to defaults */
8422 108793344 table->default_column_bitmaps();
8423 /* Reset the handler flags used for dupilcate record handling */
8424
1/2
✓ Branch 0 taken 108793826 times.
✗ Branch 1 not taken.
108793659 table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
8425
1/2
✓ Branch 0 taken 108794302 times.
✗ Branch 1 not taken.
108793826 table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
8426 /* Reset information about pushed engine conditions */
8427 108794302 pushed_cond = nullptr;
8428 /* Reset information about pushed index conditions */
8429
1/2
✓ Branch 0 taken 108791870 times.
✗ Branch 1 not taken.
108794302 cancel_pushed_idx_cond();
8430 // Forget the record buffer.
8431 108791870 m_record_buffer = nullptr;
8432 108791870 m_unique = nullptr;
8433
8434
1/2
✓ Branch 0 taken 108794016 times.
✗ Branch 1 not taken.
108791870 const int retval = reset();
8435 108794592 return retval;
8436 108794016 }
8437
8438 #ifdef WITH_WSREP
8439 6468525 static int wsrep_after_row(THD *thd) {
8440
1/2
✓ Branch 0 taken 6468530 times.
✗ Branch 1 not taken.
6468525 DBUG_TRACE;
8441
8442 /* enforce wsrep_max_ws_rows */
8443 6468530 thd->wsrep_affected_rows++;
8444
6/8
✓ Branch 0 taken 60366 times.
✓ Branch 1 taken 6408164 times.
✓ Branch 2 taken 60366 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60366 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 6468512 times.
6528896 if (wsrep_max_ws_rows && wsrep_thd_is_local(thd) &&
8445
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 60348 times.
60366 thd->wsrep_affected_rows > wsrep_max_ws_rows) {
8446
4/8
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
18 trans_rollback_stmt(thd) || trans_rollback(thd);
8447
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 my_message(ER_ERROR_DURING_COMMIT, "wsrep_max_ws_rows exceeded", MYF(0));
8448 18 return ER_ERROR_DURING_COMMIT;
8449
3/4
✓ Branch 0 taken 6468512 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 6468508 times.
6468512 } else if (wsrep_after_row(thd, false)) {
8450 4 return ER_LOCK_DEADLOCK;
8451 }
8452 6468508 return 0;
8453 6468530 }
8454 #endif /* WITH_WSREP */
8455
8456 145202077 int handler::ha_write_row(uchar *buf) {
8457 int error;
8458 145202077 Log_func *log_func = Write_rows_log_event::binlog_row_logging_function;
8459
3/4
✓ Branch 0 taken 58792471 times.
✓ Branch 1 taken 86409606 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58792471 times.
145202077 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
8460
8461
1/2
✓ Branch 0 taken 124232248 times.
✗ Branch 1 not taken.
145202077 DBUG_TRACE;
8462
4/6
✓ Branch 0 taken 123284270 times.
✓ Branch 1 taken 947686 times.
✓ Branch 2 taken 123284420 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 141429202 times.
✗ Branch 5 not taken.
124232248 DEBUG_SYNC(ha_thd(), "start_ha_write_row");
8463
3/4
✓ Branch 0 taken 145203908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 145203907 times.
142376888 DBUG_EXECUTE_IF("inject_error_ha_write_row", return HA_ERR_INTERNAL_ERROR;);
8464
2/4
✓ Branch 0 taken 145203881 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 145203881 times.
145203907 DBUG_EXECUTE_IF("simulate_storage_engine_out_of_memory",
8465 return HA_ERR_SE_OUT_OF_MEMORY;);
8466
1/2
✓ Branch 0 taken 145202979 times.
✗ Branch 1 not taken.
145203881 mark_trx_read_write();
8467
8468
2/8
✓ Branch 0 taken 145203493 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 145203493 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
145202979 DBUG_EXECUTE_IF(
8469 "handler_crashed_table_on_usage",
8470 my_error(HA_ERR_CRASHED, MYF(ME_ERRORLOG), table_share->table_name.str);
8471 set_my_errno(HA_ERR_CRASHED); return HA_ERR_CRASHED;);
8472
8473
9/27
✓ Branch 0 taken 43765618 times.
✓ Branch 1 taken 101437875 times.
✓ Branch 2 taken 43766058 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 43765311 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 43766061 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 42651733 times.
✓ Branch 10 taken 1114328 times.
✓ Branch 11 taken 42651927 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✓ Branch 25 taken 101437778 times.
✗ Branch 26 not taken.
145203493 MYSQL_TABLE_IO_WAIT(PSI_TABLE_WRITE_ROW, MAX_KEY, error,
8474 { error = write_row(buf); })
8475
8476
2/2
✓ Branch 0 taken 4784041 times.
✓ Branch 1 taken 140420006 times.
145204033 if (unlikely(error)) return error;
8477
8478
3/4
✓ Branch 0 taken 140419074 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 140419572 times.
140420006 if (unlikely((error = binlog_log_row(table, nullptr, buf, log_func))))
8479 4 return error; /* purecov: inspected */
8480
8481 #ifdef WITH_WSREP
8482 /* With MySQL-8.0 DDL action would result in altering of InnoDB
8483 system table. Logic below should avoid considering alter of InnoDB
8484 system table to increase affected rows. To cover the same, logic
8485 is now expanded to include binlog check. InnoDB flow suppresses
8486 binlogging of the changes that it does to DDL table as part of DDL
8487 execution. */
8488
13/16
✓ Branch 0 taken 140420013 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 140420051 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17716619 times.
✓ Branch 5 taken 122703432 times.
✓ Branch 6 taken 9942387 times.
✓ Branch 7 taken 7774232 times.
✓ Branch 8 taken 9942388 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9370640 times.
✓ Branch 11 taken 571748 times.
✓ Branch 12 taken 5689619 times.
✓ Branch 13 taken 3681021 times.
✓ Branch 14 taken 5430004 times.
✓ Branch 15 taken 134990012 times.
146109193 if (WSREP(ha_thd()) && table->s->tmp_table == NO_TMP_TABLE &&
8489
4/6
✓ Branch 0 taken 5689621 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5689621 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5430005 times.
✓ Branch 5 taken 259616 times.
5689619 check_table_binlog_row_based(ha_thd(), table)) {
8490
4/6
✓ Branch 0 taken 5430003 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5430005 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 5429990 times.
5430004 if ((error = wsrep_after_row(ha_thd()))) {
8491 15 return error;
8492 }
8493 }
8494 #endif /* WITH_WSREP */
8495
8496 140420002 rows_changed++;
8497
8498
3/4
✓ Branch 0 taken 136677715 times.
✓ Branch 1 taken 3742287 times.
✓ Branch 2 taken 136677834 times.
✗ Branch 3 not taken.
140420002 DEBUG_SYNC_C("ha_write_row_end");
8499 140420121 return 0;
8500 145204182 }
8501
8502 20261142 int handler::ha_update_row(const uchar *old_data, uchar *new_data) {
8503 int error;
8504
3/4
✓ Branch 0 taken 13765047 times.
✓ Branch 1 taken 6496095 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13765047 times.
20261142 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
8505 20261142 Log_func *log_func = Update_rows_log_event::binlog_row_logging_function;
8506
8507 /*
8508 Some storage engines require that the new record is in record[0]
8509 (and the old record is in record[1]).
8510 */
8511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20261142 times.
20261142 assert(new_data == table->record[0]);
8512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20261142 times.
20261142 assert(old_data == table->record[1]);
8513
8514 20261142 mark_trx_read_write();
8515
8516
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20261150 times.
20261155 DBUG_EXECUTE_IF(
8517 "handler_crashed_table_on_usage",
8518 my_error(HA_ERR_CRASHED, MYF(ME_ERRORLOG), table_share->table_name.str);
8519 set_my_errno(HA_ERR_CRASHED); return (HA_ERR_CRASHED););
8520
8521
11/19
✓ Branch 0 taken 4264617 times.
✓ Branch 1 taken 15996533 times.
✓ Branch 2 taken 4263819 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 798 times.
✓ Branch 5 taken 4263819 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 4263807 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 4262903 times.
✓ Branch 10 taken 904 times.
✓ Branch 11 taken 4262903 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 798 times.
✓ Branch 17 taken 798 times.
✗ Branch 18 not taken.
20261150 MYSQL_TABLE_IO_WAIT(PSI_TABLE_UPDATE_ROW, active_index, error,
8522 { error = update_row(old_data, new_data); })
8523
8524
2/2
✓ Branch 0 taken 7292374 times.
✓ Branch 1 taken 12968768 times.
20261133 if (unlikely(error)) return error;
8525
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12968765 times.
12968768 if (unlikely((error = binlog_log_row(table, old_data, new_data, log_func))))
8526 2 return error;
8527
8528 #ifdef WITH_WSREP
8529 /* With MySQL-8.0 DDL action would result in altering of InnoDB
8530 system table. Logic below should avoid considering alter of InnoDB
8531 system table to increase affected rows. To cover the same, logic
8532 is now expanded to include binlog check. InnoDB flow suppresses
8533 binlogging of the changes that it does to DDL table as part of DDL
8534 execution. */
8535
11/12
✓ Branch 0 taken 12968772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1415099 times.
✓ Branch 3 taken 11553673 times.
✓ Branch 4 taken 1105976 times.
✓ Branch 5 taken 309123 times.
✓ Branch 6 taken 1100705 times.
✓ Branch 7 taken 5271 times.
✓ Branch 8 taken 1089471 times.
✓ Branch 9 taken 11234 times.
✓ Branch 10 taken 1014157 times.
✓ Branch 11 taken 11954607 times.
14058229 if (WSREP(ha_thd()) && table->s->tmp_table == NO_TMP_TABLE &&
8536
2/2
✓ Branch 0 taken 1014157 times.
✓ Branch 1 taken 75307 times.
1089471 check_table_binlog_row_based(ha_thd(), table)) {
8537
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1014160 times.
1014157 if ((error = wsrep_after_row(ha_thd()))) {
8538 3 return error;
8539 }
8540 }
8541 #endif /* WITH_WSREP */
8542
8543 12968767 rows_changed++;
8544 12968767 return 0;
8545 }
8546
8547 9764495 int handler::ha_delete_row(const uchar *buf) {
8548 int error;
8549
3/4
✓ Branch 0 taken 9758854 times.
✓ Branch 1 taken 5641 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9758854 times.
9764495 assert(table_share->tmp_table != NO_TMP_TABLE || m_lock_type == F_WRLCK);
8550 9764495 Log_func *log_func = Delete_rows_log_event::binlog_row_logging_function;
8551 /*
8552 Normally table->record[0] is used, but sometimes table->record[1] is used.
8553 */
8554
3/4
✓ Branch 0 taken 7327708 times.
✓ Branch 1 taken 2436787 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7327708 times.
9764495 assert(buf == table->record[0] || buf == table->record[1]);
8555
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9764496 times.
9764495 DBUG_EXECUTE_IF("inject_error_ha_delete_row", return HA_ERR_INTERNAL_ERROR;);
8556
8557
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9764496 times.
9764496 DBUG_EXECUTE_IF(
8558 "handler_crashed_table_on_usage",
8559 my_error(HA_ERR_CRASHED, MYF(ME_ERRORLOG), table_share->table_name.str);
8560 set_my_errno(HA_ERR_CRASHED); return (HA_ERR_CRASHED););
8561
8562 9764496 mark_trx_read_write();
8563
8564
13/19
✓ Branch 0 taken 2148024 times.
✓ Branch 1 taken 7616473 times.
✓ Branch 2 taken 2147851 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 172 times.
✓ Branch 5 taken 2147851 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2147851 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2147824 times.
✓ Branch 10 taken 27 times.
✓ Branch 11 taken 2147824 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 172 times.
✓ Branch 17 taken 172 times.
✗ Branch 18 not taken.
9764497 MYSQL_TABLE_IO_WAIT(PSI_TABLE_DELETE_ROW, active_index, error,
8565 { error = delete_row(buf); })
8566
8567
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 9764419 times.
9764497 if (unlikely(error)) return error;
8568
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9764417 times.
9764419 if (unlikely((error = binlog_log_row(table, buf, nullptr, log_func))))
8569 2 return error;
8570
8571 #ifdef WITH_WSREP
8572 /* With MySQL-8.0 DDL action would result in altering of InnoDB
8573 system table. Logic below should avoid considering alter of InnoDB
8574 system table to increase affected rows. To cover the same, logic
8575 is now expanded to include binlog check. InnoDB flow suppresses
8576 binlogging of the changes that it does to DDL table as part of DDL
8577 execution. */
8578
10/12
✓ Branch 0 taken 9764417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4460100 times.
✓ Branch 3 taken 5304317 times.
✓ Branch 4 taken 223260 times.
✓ Branch 5 taken 4236840 times.
✓ Branch 6 taken 135695 times.
✓ Branch 7 taken 87565 times.
✓ Branch 8 taken 135695 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 24368 times.
✓ Branch 11 taken 9740049 times.
9900112 if (WSREP(ha_thd()) && table->s->tmp_table == NO_TMP_TABLE &&
8579
2/2
✓ Branch 0 taken 24368 times.
✓ Branch 1 taken 111327 times.
135695 check_table_binlog_row_based(ha_thd(), table)) {
8580
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24364 times.
24368 if ((error = wsrep_after_row(ha_thd()))) {
8581 4 return error;
8582 }
8583 }
8584 #endif /* WITH_WSREP */
8585
8586 9764413 rows_changed++;
8587 9764413 return 0;
8588 }
8589
8590 /**
8591 @brief Offload an update to the storage engine. See handler::fast_update()
8592 for details.
8593 */
8594 166135 int handler::ha_fast_update(THD *thd, mem_root_deque<Item *> &update_fields,
8595 mem_root_deque<Item *> &update_values,
8596 Item *conds) {
8597 166135 int error = fast_update(thd, update_fields, update_values, conds);
8598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 166137 times.
166137 if (error == 0) mark_trx_read_write();
8599 166154 return error;
8600 }
8601
8602 /**
8603 @brief Offload an upsert to the storage engine. See handler::upsert()
8604 for details.
8605 */
8606 8567271 int handler::ha_upsert(THD *thd, mem_root_deque<Item *> &update_fields,
8607 mem_root_deque<Item *> &update_values) {
8608 8567271 int error = upsert(thd, update_fields, update_values);
8609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8567374 times.
8567374 if (error == 0) mark_trx_read_write();
8610 8567502 return error;
8611 }
8612
8613 /** @brief
8614 use_hidden_primary_key() is called in case of an update/delete when
8615 (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined
8616 but we don't have a primary key
8617 */
8618 void handler::use_hidden_primary_key() {
8619 /* fallback to use all columns in the table to identify row */
8620 table->use_all_columns();
8621 }
8622
8623 /**
8624 Get an initialized ha_share.
8625
8626 @return Initialized ha_share
8627 @retval NULL ha_share is not yet initialized.
8628 @retval != NULL previous initialized ha_share.
8629
8630 @note
8631 If not a temp table, then LOCK_ha_data must be held.
8632 */
8633
8634 159360 Handler_share *handler::get_ha_share_ptr() {
8635
1/2
✓ Branch 0 taken 159360 times.
✗ Branch 1 not taken.
159360 DBUG_TRACE;
8636
2/4
✓ Branch 0 taken 159360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 159360 times.
✗ Branch 3 not taken.
159360 assert(ha_share && table_share);
8637
8638 #ifndef NDEBUG
8639 159360 if (table_share->tmp_table == NO_TMP_TABLE)
8640 mysql_mutex_assert_owner(&table_share->LOCK_ha_data);
8641 #endif
8642
8643 159360 return *ha_share;
8644 159360 }
8645
8646 /**
8647 Set ha_share to be used by all instances of the same table/partition.
8648
8649 @param arg_ha_share Handler_share to be shared.
8650
8651 @note
8652 If not a temp table, then LOCK_ha_data must be held.
8653 */
8654
8655 149108 void handler::set_ha_share_ptr(Handler_share *arg_ha_share) {
8656
1/2
✓ Branch 0 taken 149108 times.
✗ Branch 1 not taken.
149108 DBUG_TRACE;
8657
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149108 times.
149108 assert(ha_share);
8658 #ifndef NDEBUG
8659 149108 if (table_share->tmp_table == NO_TMP_TABLE)
8660 mysql_mutex_assert_owner(&table_share->LOCK_ha_data);
8661 #endif
8662
8663 149108 *ha_share = arg_ha_share;
8664 149108 }
8665
8666 /**
8667 Take a lock for protecting shared handler data.
8668 */
8669
8670 556092 void handler::lock_shared_ha_data() {
8671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 556092 times.
556092 assert(table_share);
8672
2/2
✓ Branch 0 taken 289076 times.
✓ Branch 1 taken 267016 times.
556092 if (table_share->tmp_table == NO_TMP_TABLE)
8673 289076 mysql_mutex_lock(&table_share->LOCK_ha_data);
8674 556092 }
8675
8676 /**
8677 Release lock for protecting ha_share.
8678 */
8679
8680 556092 void handler::unlock_shared_ha_data() {
8681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 556092 times.
556092 assert(table_share);
8682
2/2
✓ Branch 0 taken 289076 times.
✓ Branch 1 taken 267016 times.
556092 if (table_share->tmp_table == NO_TMP_TABLE)
8683 289076 mysql_mutex_unlock(&table_share->LOCK_ha_data);
8684 556092 }
8685
8686 #ifdef WITH_WSREP
8687 /**
8688 @details
8689 This function makes the storage engine to force the victim transaction
8690 to abort. Currently, only innodb has this functionality, but any SE
8691 implementing the wsrep API should provide this service to support
8692 multi-master operation.
8693
8694 @param bf_thd brute force THD asking for the abort
8695 @param victim_thd victim THD to be aborted
8696
8697 @return
8698 always 0
8699 */
8700
8701 174 int ha_wsrep_abort_transaction(THD *bf_thd, THD *victim_thd, bool signal) {
8702
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 DBUG_ENTER("ha_wsrep_abort_transaction");
8703
8704 // Proceed with abort only if wsrep_on=1 or THD in in RSU
8705
7/12
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 174 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 172 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
174 bool do_abort = WSREP(bf_thd) || wsrep_thd_is_in_rsu(bf_thd);
8706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
174 if (!do_abort) {
8707 DBUG_RETURN(0);
8708 }
8709
8710 174 handlerton *hton = installed_htons[DB_TYPE_INNODB];
8711
2/4
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✗ Branch 3 not taken.
174 if (hton && hton->wsrep_abort_transaction) {
8712
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 hton->wsrep_abort_transaction(hton, bf_thd, victim_thd, signal);
8713 } else {
8714 WSREP_WARN("cannot abort InnoDB transaction");
8715 }
8716
8717
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 DBUG_RETURN(0);
8718 }
8719 #endif /* WITH_WSREP */
8720
8721 /**
8722 This structure is a helper structure for passing the length and pointer of
8723 blob space allocated by storage engine.
8724 */
8725 struct blob_len_ptr {
8726 uint length; // length of the blob
8727 uchar *ptr; // pointer of the value
8728 };
8729
8730 /**
8731 Get the blob length and pointer of allocated space from the record buffer.
8732
8733 During evaluating the blob virtual generated columns, the blob space will
8734 be allocated by server. In order to keep the blob data after the table is
8735 closed, we need write the data into a specified space allocated by storage
8736 engine. Here, we have to extract the space pointer and length from the
8737 record buffer.
8738 After we get the value of virtual generated columns, copy the data into
8739 the specified space and store it in the record buffer (@see copy_blob_data()).
8740
8741 @param table the pointer of table
8742 @param fields bitmap of field index of evaluated
8743 generated column
8744 @param[out] blob_len_ptr_array an array to record the length and pointer
8745 of allocated space by storage engine.
8746 @note The caller should provide the blob_len_ptr_array with a size of
8747 MAX_FIELDS.
8748 */
8749
8750 static void extract_blob_space_and_length_from_record_buff(
8751 const TABLE *table, const MY_BITMAP *const fields,
8752 blob_len_ptr *blob_len_ptr_array) {
8753 int num = 0;
8754 for (Field **vfield = table->vfield; *vfield; vfield++) {
8755 // Check if this field should be included
8756 if (bitmap_is_set(fields, (*vfield)->field_index()) &&
8757 (*vfield)->is_virtual_gcol() && (*vfield)->type() == MYSQL_TYPE_BLOB) {
8758 auto field = down_cast<Field_blob *>(*vfield);
8759 blob_len_ptr_array[num].length = field->data_length();
8760 // TODO: The following check is only for Innodb.
8761 assert(blob_len_ptr_array[num].length == 255 ||
8762 blob_len_ptr_array[num].length == 768 ||
8763 blob_len_ptr_array[num].length == 3073);
8764
8765 blob_len_ptr_array[num].ptr = field->get_blob_data();
8766
8767 // Let server allocate the space for BLOB virtual generated columns
8768 field->reset();
8769
8770 num++;
8771 assert(num <= MAX_FIELDS);
8772 }
8773 }
8774 }
8775
8776 /**
8777 Copy the value of BLOB virtual generated columns into the space allocated
8778 by storage engine.
8779
8780 This is because the table is closed after evaluating the value. In order to
8781 keep the BLOB value after the table is closed, we have to copy the value into
8782 the place where storage engine prepares for.
8783
8784 @param table pointer of the table to be operated on
8785 @param fields bitmap of field index of evaluated generated column
8786 @param blob_len_ptr_array array of length and pointer of allocated space by
8787 storage engine.
8788 */
8789
8790 static void copy_blob_data(const TABLE *table, const MY_BITMAP *const fields,
8791 blob_len_ptr *blob_len_ptr_array) {
8792 uint num = 0;
8793 for (Field **vfield = table->vfield; *vfield; vfield++) {
8794 // Check if this field should be included
8795 if (bitmap_is_set(fields, (*vfield)->field_index()) &&
8796 (*vfield)->is_virtual_gcol() && (*vfield)->type() == MYSQL_TYPE_BLOB) {
8797 assert(blob_len_ptr_array[num].length > 0);
8798 assert(blob_len_ptr_array[num].ptr != nullptr);
8799
8800 /*
8801 Only copy as much of the blob as the storage engine has
8802 allocated space for. This is sufficient since the only use of the
8803 blob in the storage engine is for using a prefix of it in a
8804 secondary index.
8805 */
8806 uint length = (*vfield)->data_length();
8807 const uint alloc_len = blob_len_ptr_array[num].length;
8808 length = length > alloc_len ? alloc_len : length;
8809
8810 Field_blob *blob_field = down_cast<Field_blob *>(*vfield);
8811 memcpy(blob_len_ptr_array[num].ptr, blob_field->get_blob_data(), length);
8812 blob_field->store_in_allocated_space(
8813 pointer_cast<char *>(blob_len_ptr_array[num].ptr), length);
8814 num++;
8815 assert(num <= MAX_FIELDS);
8816 }
8817 }
8818 }
8819
8820 88361831 bool handler::is_using_prohibited_gap_locks(
8821 TABLE *table, bool using_full_primary_key) const noexcept {
8822 88361831 const THD *thd = table->in_use;
8823 88361831 const thr_lock_type lock_type = table->reginfo.lock_type;
8824
8825
4/4
✓ Branch 0 taken 35617915 times.
✓ Branch 1 taken 13303798 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 35617717 times.
48921693 if (!using_full_primary_key && has_transactions() && !has_gap_locks() &&
8826
3/4
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 136 times.
✗ Branch 3 not taken.
126 thd_tx_isolation(thd) >= ISO_REPEATABLE_READ && !thd->rli_slave &&
8827
4/6
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 107 times.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
136 (thd->lex->table_count >= 2 || thd->in_multi_stmt_transaction_mode()) &&
8828
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 (lock_type >= TL_WRITE_ALLOW_WRITE ||
8829
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 lock_type == TL_READ_WITH_SHARED_LOCKS ||
8830
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 lock_type == TL_READ_NO_INSERT ||
8831
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 27 times.
29 (lock_type != TL_IGNORE && thd->lex->sql_command != SQLCOM_SELECT)) &&
8832
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 thd->lex->sql_command != SQLCOM_ALTER_TABLE &&
8833
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 thd->lex->sql_command != SQLCOM_CREATE_INDEX &&
8834
5/6
✓ Branch 0 taken 48921693 times.
✓ Branch 1 taken 39440138 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 88361790 times.
137283487 thd->lex->sql_command != SQLCOM_CHECK &&
8835
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 thd->lex->sql_command != SQLCOM_OPTIMIZE) {
8836 2 my_printf_error(ER_UNKNOWN_ERROR,
8837 "Using Gap Lock without full unique key in multi-table "
8838 "or multi-statement transactions is not "
8839 "allowed. You need to either rewrite queries to use "
8840 "all unique key columns in WHERE equal conditions, or "
8841 "rewrite to single-table, single-statement "
8842 "transaction. Query: %s",
8843 2 MYF(0), thd->query().str);
8844 2 return true;
8845 }
8846 88361790 return false;
8847 }
8848
8849 /*
8850 Evaluate generated column's value. This is an internal helper reserved for
8851 handler::my_eval_gcolumn_expr().
8852
8853 @param thd pointer of THD
8854 @param table The pointer of table where evaluated generated
8855 columns are in
8856 @param fields bitmap of field index of evaluated generated column
8857 @param[in,out] record record buff of base columns generated column depends.
8858 After calling this function, it will be used to return
8859 the value of generated column.
8860 @param in_purge whether the function is called by purge thread
8861
8862 @return true in case of error, false otherwise.
8863 */
8864
8865 29708 static bool my_eval_gcolumn_expr_helper(THD *thd, TABLE *table,
8866 const MY_BITMAP *const fields,
8867 uchar *record, bool in_purge,
8868 const char **mv_data_ptr,
8869 ulong *mv_length) {
8870
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 DBUG_TRACE;
8871
2/4
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29708 times.
✗ Branch 3 not taken.
29708 assert(table && table->vfield);
8872
2/4
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29708 times.
29708 assert(!thd->is_error());
8873
8874 29708 uchar *old_buf = table->record[0];
8875
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 repoint_field_to_record(table, old_buf, record);
8876
8877 blob_len_ptr blob_len_ptr_array[MAX_FIELDS];
8878
8879 /*
8880 If it's purge thread, we need get the space allocated by storage engine
8881 for blob.
8882 */
8883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29708 times.
29708 if (in_purge)
8884 extract_blob_space_and_length_from_record_buff(table, fields,
8885 blob_len_ptr_array);
8886
8887 29708 bool res = false;
8888 29708 Field *mv_field = nullptr;
8889 29708 MY_BITMAP fields_to_evaluate;
8890 my_bitmap_map bitbuf[bitmap_buffer_size(MAX_FIELDS) / sizeof(my_bitmap_map)];
8891
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 bitmap_init(&fields_to_evaluate, bitbuf, table->s->fields);
8892 29708 bitmap_set_all(&fields_to_evaluate);
8893
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 bitmap_intersect(&fields_to_evaluate, fields);
8894 /*
8895 In addition to evaluating the value for the columns requested by
8896 the caller we also need to evaluate any virtual columns that these
8897 depend on.
8898 This loop goes through the columns that should be evaluated and
8899 adds all the base columns. If the base column is virtual, it has
8900 to be evaluated.
8901 */
8902
2/2
✓ Branch 0 taken 37750 times.
✓ Branch 1 taken 29708 times.
67458 for (Field **vfield_ptr = table->vfield; *vfield_ptr; vfield_ptr++) {
8903 37750 Field *field = *vfield_ptr;
8904 // Validate that the field number is less than the bit map size
8905
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37750 times.
37750 assert(field->field_index() < fields->n_bits);
8906
8907
2/2
✓ Branch 0 taken 29708 times.
✓ Branch 1 taken 8042 times.
37750 if (bitmap_is_set(fields, field->field_index())) {
8908
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 bitmap_union(&fields_to_evaluate, &field->gcol_info->base_columns_map);
8909
3/4
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25433 times.
✓ Branch 3 taken 4275 times.
29708 if (field->is_array()) {
8910 25433 mv_field = field;
8911 // Backup current value and use dedicated temporary buffer
8912
2/4
✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25433 times.
25433 if ((down_cast<Field_blob *>(field))->backup_blob_field()) return true;
8913 }
8914 }
8915 }
8916
8917 /*
8918 Evaluate all requested columns and all base columns these depends
8919 on that are virtual.
8920
8921 This function is called by the storage engine, which may request to
8922 evaluate more generated columns than read_set/write_set says.
8923 For example, InnoDB's row_sel_sec_rec_is_for_clust_rec() reads the full
8924 record from the clustered index and asks us to compute generated columns
8925 that match key fields in the used secondary index. So we trust that the
8926 engine has filled all base columns necessary to requested computations,
8927 and we ignore read_set/write_set.
8928 */
8929
8930 my_bitmap_map *old_maps[2];
8931 29708 dbug_tmp_use_all_columns(table, old_maps, table->read_set, table->write_set);
8932
8933
2/2
✓ Branch 0 taken 37750 times.
✓ Branch 1 taken 29674 times.
67424 for (Field **vfield_ptr = table->vfield; *vfield_ptr; vfield_ptr++) {
8934 37750 Field *field = *vfield_ptr;
8935
8936 // Check if we should evaluate this field
8937
5/6
✓ Branch 0 taken 29714 times.
✓ Branch 1 taken 8036 times.
✓ Branch 2 taken 29714 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29714 times.
✓ Branch 5 taken 8036 times.
67464 if (bitmap_is_set(&fields_to_evaluate, field->field_index()) &&
8938 29714 field->is_virtual_gcol()) {
8939
2/4
✓ Branch 0 taken 29714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29714 times.
✗ Branch 3 not taken.
29714 assert(field->gcol_info && field->gcol_info->expr_item->fixed);
8940
8941 const type_conversion_status save_in_field_status =
8942
1/2
✓ Branch 0 taken 29714 times.
✗ Branch 1 not taken.
29714 field->gcol_info->expr_item->save_in_field(field, false);
8943
4/6
✓ Branch 0 taken 29714 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 29680 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
29714 assert(!thd->is_error() || save_in_field_status != TYPE_OK);
8944
8945 /*
8946 save_in_field() may return non-zero even if there was no
8947 error. This happens if a warning is raised, such as an
8948 out-of-range warning when converting the result to the target
8949 type of the virtual column. We should stop only if the
8950 non-zero return value was caused by an actual error.
8951 */
8952
7/8
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 29673 times.
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 34 times.
✓ Branch 7 taken 29680 times.
29714 if (save_in_field_status != TYPE_OK && thd->is_error()) {
8953 34 res = true;
8954 34 break;
8955 }
8956 }
8957 }
8958
8959 29708 dbug_tmp_restore_column_maps(table->read_set, table->write_set, old_maps);
8960
8961 /*
8962 If it's a purge thread, we need copy the blob data into specified place
8963 allocated by storage engine so that the blob data still can be accessed
8964 after table is closed.
8965 */
8966
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 29708 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
29708 if (in_purge) copy_blob_data(table, fields, blob_len_ptr_array);
8967
8968
2/2
✓ Branch 0 taken 25433 times.
✓ Branch 1 taken 4275 times.
29708 if (mv_field) {
8969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25433 times.
25433 assert(mv_data_ptr);
8970 25433 Field_json *fld = down_cast<Field_json *>(mv_field);
8971 // Save calculated value
8972
1/2
✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
25433 *mv_data_ptr = fld->get_binary();
8973
1/2
✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
25433 *mv_length = fld->data_length();
8974 // Restore original value
8975
1/2
✓ Branch 0 taken 25433 times.
✗ Branch 1 not taken.
25433 (fld)->restore_blob_backup();
8976 }
8977
8978
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 repoint_field_to_record(table, record, old_buf);
8979 29708 return res;
8980 29708 }
8981
8982 // Set se_private_id and se_private_data during upgrade
8983 5044 bool handler::ha_upgrade_table(THD *thd, const char *dbname,
8984 const char *table_name, dd::Table *dd_table,
8985 TABLE *table_arg) {
8986 5044 table = table_arg;
8987 5044 return upgrade_table(thd, dbname, table_name, dd_table);
8988 }
8989
8990 /**
8991 Callback to allow InnoDB to prepare a template for generated
8992 column processing. This function will open the table without
8993 opening in the engine and call the provided function with
8994 the TABLE object made. The function will then close the TABLE.
8995
8996 @param thd Thread handle
8997 @param db_name Name of database containing the table
8998 @param table_name Name of table to open
8999 @param myc InnoDB function to call for processing TABLE
9000 @param ib_table Argument for InnoDB function
9001
9002 @return true in case of error, false otherwise.
9003 */
9004
9005 2 bool handler::my_prepare_gcolumn_template(THD *thd, const char *db_name,
9006 const char *table_name,
9007 my_gcolumn_template_callback_t myc,
9008 void *ib_table) {
9009 2 bool rc = true;
9010 2 Temp_table_handle tblhdl;
9011
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 TABLE *table = tblhdl.open(thd, db_name, table_name);
9012
9013
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (table) {
9014
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 myc(table, ib_table);
9015 2 rc = false;
9016 }
9017 2 return rc;
9018 2 }
9019
9020 /**
9021 Callback for generated columns processing. Will open the table, in the
9022 server *only*, and call my_eval_gcolumn_expr_helper() to do the actual
9023 processing. This function is a variant of the other
9024 handler::my_eval_gcolumn_expr() but is intended for use when no TABLE
9025 object already exists - e.g. from purge threads.
9026
9027 Note! The call to open_table_uncached() must be made with the second-to-last
9028 argument (open_in_engine) set to false. Failing to do so will cause
9029 deadlocks and incorrect behavior.
9030
9031 @param thd thread handle
9032 @param db_name database containing the table to open
9033 @param table_name name of table to open
9034 @param fields bitmap of field index of evaluated generated column
9035 @param record record buffer
9036 @param[out] mv_data_ptr For a typed array field in this arg the pointer
9037 to its value is returned
9038 @param[out] mv_length Length of the value above
9039
9040 @return true in case of error, false otherwise.
9041 */
9042
9043 bool handler::my_eval_gcolumn_expr_with_open(THD *thd, const char *db_name,
9044 const char *table_name,
9045 const MY_BITMAP *const fields,
9046 uchar *record,
9047 const char **mv_data_ptr,
9048 ulong *mv_length) {
9049 bool retval = true;
9050 Temp_table_handle tblhdl;
9051 TABLE *table = tblhdl.open(thd, db_name, table_name);
9052
9053 if (table) {
9054 retval = my_eval_gcolumn_expr_helper(thd, table, fields, record, true,
9055 mv_data_ptr, mv_length);
9056 }
9057
9058 return retval;
9059 }
9060
9061 29708 bool handler::my_eval_gcolumn_expr(THD *thd, TABLE *table,
9062 const MY_BITMAP *const fields, uchar *record,
9063 const char **mv_data_ptr, ulong *mv_length) {
9064
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 DBUG_TRACE;
9065
9066
1/2
✓ Branch 0 taken 29708 times.
✗ Branch 1 not taken.
29708 const bool res = my_eval_gcolumn_expr_helper(thd, table, fields, record,
9067 false, mv_data_ptr, mv_length);
9068 29708 return res;
9069 29708 }
9070
9071 1448 bool handler::filter_dup_records() {
9072
2/4
✓ Branch 0 taken 1448 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1448 times.
✗ Branch 3 not taken.
1448 assert(inited == INDEX && m_unique);
9073 1448 position(table->record[0]);
9074 1448 return m_unique->unique_add(ref);
9075 }
9076
9077 738293326 int handler::ha_extra(enum ha_extra_function operation) {
9078
2/2
✓ Branch 0 taken 506 times.
✓ Branch 1 taken 738292820 times.
738293326 if (operation == HA_EXTRA_ENABLE_UNIQUE_RECORD_FILTER) {
9079 // This operation should be called only for active multi-valued index
9080
2/4
✓ Branch 0 taken 506 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 506 times.
✗ Branch 3 not taken.
506 assert(inited == INDEX &&
9081 (table->key_info[active_index].flags & HA_MULTI_VALUED_KEY));
9082 // This unique filter uses only row id to weed out duplicates. Due to that
9083 // it will work with any active index.
9084
3/4
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 506 times.
1006 if (!m_unique &&
9085
2/4
✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 500 times.
✗ Branch 3 not taken.
500 (!(m_unique = new (*THR_MALLOC) Unique_on_insert(ref_length)) ||
9086
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
500 m_unique->init())) {
9087 /* purecov: begin inspected */
9088 destroy(m_unique);
9089 return HA_ERR_OUT_OF_MEM;
9090 /* purecov: end */
9091 }
9092 506 m_unique->reset(true);
9093 506 return 0;
9094
2/2
✓ Branch 0 taken 580 times.
✓ Branch 1 taken 738292240 times.
738292820 } else if (operation == HA_EXTRA_DISABLE_UNIQUE_RECORD_FILTER) {
9095
2/2
✓ Branch 0 taken 448 times.
✓ Branch 1 taken 132 times.
580 if (m_unique) {
9096 448 m_unique->cleanup();
9097 448 destroy(m_unique);
9098 448 m_unique = nullptr;
9099 }
9100 }
9101 738292820 return extra(operation);
9102 }
9103
9104 204 TABLE *Temp_table_handle::open(THD *thd, const char *db_name,
9105 const char *table_name) {
9106 char path[FN_REFLEN + 1];
9107 bool was_truncated;
9108
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 build_table_filename(path, sizeof(path) - 1 - reg_ext_length, db_name,
9109 table_name, "", 0, &was_truncated);
9110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 assert(!was_truncated);
9111
9112 204 MDL_request table_request;
9113
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 MDL_REQUEST_INIT(&table_request, MDL_key::TABLE, db_name, table_name,
9114 MDL_SHARED, MDL_TRANSACTION);
9115
9116
2/4
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
204 if (thd->mdl_context.acquire_lock(&table_request,
9117 thd->variables.lock_wait_timeout)) {
9118 return nullptr;
9119 }
9120
9121 {
9122
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client());
9123 204 const dd::Table *tab_obj = nullptr;
9124
4/8
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 204 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 204 times.
204 if (thd->dd_client()->acquire(db_name, table_name, &tab_obj))
9125 return nullptr;
9126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
204 assert(tab_obj);
9127
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 table = open_table_uncached(thd, path, db_name, table_name, false, false,
9128 *tab_obj);
9129
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 }
9130 204 return table;
9131 }
9132
9133 29710 Temp_table_handle::~Temp_table_handle() {
9134
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 29506 times.
29710 if (table != nullptr) {
9135 204 intern_close_table(table);
9136 }
9137 29710 }
9138
9139 /**
9140 Auxiliary structure for passing information to notify_*_helper()
9141 functions.
9142 */
9143
9144 struct HTON_NOTIFY_PARAMS {
9145 7173364 HTON_NOTIFY_PARAMS(const MDL_key *mdl_key, ha_notification_type mdl_type)
9146 7173364 : key(mdl_key),
9147 7173364 notification_type(mdl_type),
9148 7173364 some_htons_were_notified(false),
9149 7173364 victimized(false) {}
9150
9151 const MDL_key *key;
9152 const ha_notification_type notification_type;
9153 bool some_htons_were_notified;
9154 bool victimized;
9155 };
9156
9157 58539471 static bool notify_exclusive_mdl_helper(THD *thd, plugin_ref plugin,
9158 void *arg) {
9159 58539471 handlerton *hton = plugin_data<handlerton *>(plugin);
9160
3/4
✓ Branch 0 taken 58411665 times.
✓ Branch 1 taken 127806 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58411665 times.
58539471 if (hton->state == SHOW_OPTION_YES && hton->notify_exclusive_mdl) {
9161 HTON_NOTIFY_PARAMS *params = reinterpret_cast<HTON_NOTIFY_PARAMS *>(arg);
9162
9163 if (hton->notify_exclusive_mdl(thd, params->key, params->notification_type,
9164 &params->victimized)) {
9165 // Ignore failures from post event notification.
9166 if (params->notification_type == HA_NOTIFY_PRE_EVENT) return true;
9167 } else
9168 params->some_htons_were_notified = true;
9169 }
9170 58539471 return false;
9171 }
9172
9173 /**
9174 Notify/get permission from all interested storage engines before
9175 acquisition or after release of exclusive metadata lock on object
9176 represented by key.
9177
9178 @param thd Thread context.
9179 @param mdl_key MDL key identifying object on which exclusive
9180 lock is to be acquired/was released.
9181 @param notification_type Indicates whether this is pre-acquire or
9182 post-release notification.
9183 @param victimized 'true' if locking failed as we were selected
9184 as a victim in order to avoid possible deadlocks.
9185
9186 See @sa handlerton::notify_exclusive_mdl for details about
9187 calling convention and error reporting.
9188
9189 @return False - if notification was successful/lock can be acquired,
9190 True - if it has failed/lock should not be acquired.
9191 */
9192
9193 6964775 bool ha_notify_exclusive_mdl(THD *thd, const MDL_key *mdl_key,
9194 ha_notification_type notification_type,
9195 bool *victimized) {
9196 6964775 HTON_NOTIFY_PARAMS params(mdl_key, notification_type);
9197 6964775 *victimized = false;
9198
2/4
✓ Branch 0 taken 6964776 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6964776 times.
6964775 if (plugin_foreach(thd, notify_exclusive_mdl_helper,
9199 MYSQL_STORAGE_ENGINE_PLUGIN, &params)) {
9200 *victimized = params.victimized;
9201 /*
9202 If some SE hasn't given its permission to acquire lock and some SEs
9203 has given their permissions, we need to notify the latter group about
9204 failed lock acquisition. We do this by calling post-release notification
9205 for all interested SEs unconditionally.
9206 */
9207 if (notification_type == HA_NOTIFY_PRE_EVENT &&
9208 params.some_htons_were_notified) {
9209 HTON_NOTIFY_PARAMS rollback_params(mdl_key, HA_NOTIFY_POST_EVENT);
9210 (void)plugin_foreach(thd, notify_exclusive_mdl_helper,
9211 MYSQL_STORAGE_ENGINE_PLUGIN, &rollback_params);
9212 }
9213 return true;
9214 }
9215 6964776 return false;
9216 }
9217
9218 2294631 static bool notify_alter_table_helper(THD *thd, plugin_ref plugin, void *arg) {
9219 2294631 handlerton *hton = plugin_data<handlerton *>(plugin);
9220
3/4
✓ Branch 0 taken 2284814 times.
✓ Branch 1 taken 9817 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2284814 times.
2294631 if (hton->state == SHOW_OPTION_YES && hton->notify_alter_table) {
9221 HTON_NOTIFY_PARAMS *params = reinterpret_cast<HTON_NOTIFY_PARAMS *>(arg);
9222
9223 if (hton->notify_alter_table(thd, params->key, params->notification_type)) {
9224 // Ignore failures from post event notification.
9225 if (params->notification_type == HA_NOTIFY_PRE_EVENT) return true;
9226 } else
9227 params->some_htons_were_notified = true;
9228 }
9229 2294631 return false;
9230 }
9231
9232 /**
9233 Notify/get permission from all interested storage engines before
9234 or after executed ALTER TABLE on the table identified by key.
9235
9236 @param thd Thread context.
9237 @param mdl_key MDL key identifying table.
9238 @param notification_type Indicates whether this is pre-ALTER or
9239 post-ALTER notification.
9240
9241 See @sa handlerton::notify_alter_table for rationale,
9242 details about calling convention and error reporting.
9243
9244 @return False - if notification was successful/ALTER TABLE can
9245 proceed.
9246 True - if it has failed/ALTER TABLE should fail.
9247 */
9248
9249 208589 bool ha_notify_alter_table(THD *thd, const MDL_key *mdl_key,
9250 ha_notification_type notification_type) {
9251 208589 HTON_NOTIFY_PARAMS params(mdl_key, notification_type);
9252
9253
2/4
✓ Branch 0 taken 208589 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 208589 times.
208589 if (plugin_foreach(thd, notify_alter_table_helper,
9254 MYSQL_STORAGE_ENGINE_PLUGIN, &params)) {
9255 /*
9256 If some SE hasn't given its permission to do ALTER TABLE and some SEs
9257 has given their permissions, we need to notify the latter group about
9258 failed attemopt. We do this by calling post-ALTER TABLE notification
9259 for all interested SEs unconditionally.
9260 */
9261 if (notification_type == HA_NOTIFY_PRE_EVENT &&
9262 params.some_htons_were_notified) {
9263 HTON_NOTIFY_PARAMS rollback_params(mdl_key, HA_NOTIFY_POST_EVENT);
9264 (void)plugin_foreach(thd, notify_alter_table_helper,
9265 MYSQL_STORAGE_ENGINE_PLUGIN, &rollback_params);
9266 }
9267 return true;
9268 }
9269 208589 return false;
9270 }
9271
9272 /**
9273 Set the transaction isolation level for the next transaction and update
9274 session tracker information about the transaction isolation level.
9275
9276 @param thd THD session setting the tx_isolation.
9277 @param tx_isolation The isolation level to be set.
9278 @param one_shot True if the isolation level should be restored to
9279 session default after finishing the transaction.
9280 */
9281 131551 bool set_tx_isolation(THD *thd, enum_tx_isolation tx_isolation, bool one_shot) {
9282 131551 TX_TRACKER_GET(tst);
9283
9284
2/2
✓ Branch 0 taken 131546 times.
✓ Branch 1 taken 12 times.
131558 if (thd->variables.session_track_transaction_info <= TX_TRACK_NONE)
9285 131546 tst = nullptr;
9286
9287 131558 thd->tx_isolation = tx_isolation;
9288
9289
2/2
✓ Branch 0 taken 131034 times.
✓ Branch 1 taken 524 times.
131558 if (one_shot) {
9290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131034 times.
131034 assert(!thd->in_active_multi_stmt_transaction());
9291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 131034 times.
131034 assert(!thd->in_sub_stmt);
9292 enum enum_tx_isol_level l;
9293
5/5
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 130863 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 1 times.
131034 switch (thd->tx_isolation) {
9294 39 case ISO_READ_UNCOMMITTED:
9295 39 l = TX_ISOL_UNCOMMITTED;
9296 39 break;
9297 130863 case ISO_READ_COMMITTED:
9298 130863 l = TX_ISOL_COMMITTED;
9299 130863 break;
9300 35 case ISO_REPEATABLE_READ:
9301 35 l = TX_ISOL_REPEATABLE;
9302 35 break;
9303 96 case ISO_SERIALIZABLE:
9304 96 l = TX_ISOL_SERIALIZABLE;
9305 96 break;
9306 1 default:
9307 1 assert(0);
9308 return true;
9309 }
9310
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 131024 times.
131033 if (tst) tst->set_isol_level(thd, l);
9311
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 521 times.
524 } else if (tst) {
9312 3 tst->set_isol_level(thd, TX_ISOL_INHERIT);
9313 }
9314 131558 return false;
9315 }
9316
9317 104416 static bool post_recover_handlerton(THD *, plugin_ref plugin, void *) {
9318 104416 handlerton *hton = plugin_data<handlerton *>(plugin);
9319
9320
4/4
✓ Branch 0 taken 104165 times.
✓ Branch 1 taken 251 times.
✓ Branch 2 taken 9493 times.
✓ Branch 3 taken 94672 times.
104416 if (hton->state == SHOW_OPTION_YES && hton->post_recover)
9321 9493 hton->post_recover();
9322
9323 104413 return false;
9324 }
9325
9326 9493 void ha_post_recover(void) {
9327 9493 (void)plugin_foreach(nullptr, post_recover_handlerton,
9328 MYSQL_STORAGE_ENGINE_PLUGIN, nullptr);
9329 9490 }
9330
9331 454 void handler::ha_set_primary_handler(handler *primary_handler) {
9332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
454 assert((ht->flags & HTON_IS_SECONDARY_ENGINE) != 0);
9333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 454 times.
454 assert(primary_handler->table->s->has_secondary_engine());
9334 454 m_primary_handler = primary_handler;
9335 454 }
9336
9337 /**
9338 Checks if the database name is reserved word used by SE by invoking
9339 the handlerton method.
9340
9341 @param plugin SE plugin.
9342 @param name Database name.
9343
9344 @retval true If the name is reserved word.
9345 @retval false If the name is not reserved word.
9346 */
9347 93365 static bool is_reserved_db_name_handlerton(THD *, plugin_ref plugin,
9348 void *name) {
9349 93365 handlerton *hton = plugin_data<handlerton *>(plugin);
9350
4/4
✓ Branch 0 taken 93322 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 15589 times.
✓ Branch 3 taken 77733 times.
93365 if (hton->state == SHOW_OPTION_YES && hton->is_reserved_db_name)
9351 15589 return (hton->is_reserved_db_name(hton, (const char *)name));
9352 77776 return false;
9353 }
9354
9355 /**
9356 Check if the database name is reserved word used by SE.
9357
9358 @param name Database name.
9359
9360 @retval true If the name is a reserved word.
9361 @retval false If the name is not a reserved word.
9362 */
9363 15589 bool ha_check_reserved_db_name(const char *name) {
9364 15589 return (plugin_foreach(nullptr, is_reserved_db_name_handlerton,
9365 MYSQL_STORAGE_ENGINE_PLUGIN,
9366 15589 const_cast<char *>(name)));
9367 }
9368
9369 /**
9370 Check whether an error is index access error or not
9371 after an index read. Error other than HA_ERR_END_OF_FILE
9372 or HA_ERR_KEY_NOT_FOUND will stop next index read.
9373
9374 @param error Handler error code.
9375
9376 @retval true if error is different from HA_ERR_END_OF_FILE or
9377 HA_ERR_KEY_NOT_FOUND.
9378 @retval false if error is HA_ERR_END_OF_FILE or HA_ERR_KEY_NOT_FOUND.
9379 */
9380 28316 bool is_index_access_error(int error) {
9381
3/4
✓ Branch 0 taken 28316 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19300 times.
✓ Branch 3 taken 9016 times.
28316 return (error != HA_ERR_END_OF_FILE && error != HA_ERR_KEY_NOT_FOUND);
9382 }
9383
9384 9547 Xa_state_list::Xa_state_list(Xa_state_list::list &populated_by_tc)
9385 9547 : m_underlying{populated_by_tc} {}
9386
9387 118 enum_ha_recover_xa_state Xa_state_list::find(XID const &to_find) {
9388
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 auto found = this->m_underlying.find(to_find);
9389
1/2
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
118 if (found != this->m_underlying.end()) return found->second;
9390 return enum_ha_recover_xa_state::NOT_FOUND;
9391 }
9392
9393 389 enum_ha_recover_xa_state Xa_state_list::add(XID const &xid,
9394 enum_ha_recover_xa_state state) {
9395 389 auto previous_state = enum_ha_recover_xa_state::NOT_FOUND;
9396
9397
1/2
✓ Branch 0 taken 389 times.
✗ Branch 1 not taken.
389 auto it = this->m_underlying.find(xid);
9398
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 305 times.
389 if (it != this->m_underlying.end()) previous_state = it->second;
9399
9400
2/4
✓ Branch 0 taken 310 times.
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
389 switch (state) {
9401 310 case enum_ha_recover_xa_state::PREPARED_IN_SE: {
9402
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 271 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 6 times.
310 if (previous_state == enum_ha_recover_xa_state::NOT_FOUND ||
9403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 previous_state == enum_ha_recover_xa_state::COMMITTED ||
9404 previous_state == enum_ha_recover_xa_state::ROLLEDBACK)
9405
1/2
✓ Branch 0 taken 277 times.
✗ Branch 1 not taken.
277 this->m_underlying[xid] = state;
9406 310 break;
9407 }
9408 79 case enum_ha_recover_xa_state::PREPARED_IN_TC: {
9409
3/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
79 if (previous_state == enum_ha_recover_xa_state::NOT_FOUND ||
9410 previous_state == enum_ha_recover_xa_state::PREPARED_IN_SE)
9411
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 this->m_underlying[xid] = state;
9412 79 break;
9413 }
9414 case enum_ha_recover_xa_state::NOT_FOUND:
9415 case enum_ha_recover_xa_state::COMMITTED:
9416 case enum_ha_recover_xa_state::COMMITTED_WITH_ONEPHASE:
9417 case enum_ha_recover_xa_state::ROLLEDBACK: {
9418 assert(false);
9419 break;
9420 }
9421 }
9422 389 return previous_state;
9423 }
9424
9425 7758 Xa_state_list::instantiation_tuple Xa_state_list::new_instance() {
9426 auto mem_root =
9427
1/2
✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
7758 std::make_unique<MEM_ROOT>(PSI_INSTRUMENT_ME, tc_log_page_size / 3);
9428
1/2
✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
7758 auto map_alloc = std::make_unique<Xa_state_list::allocator>(mem_root.get());
9429
1/2
✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
7758 auto xid_map = std::make_unique<Xa_state_list::list>(*map_alloc.get());
9430
1/2
✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
7758 auto xa_list = std::make_unique<Xa_state_list>(*xid_map.get());
9431 return std::make_tuple<
9432 std::unique_ptr<MEM_ROOT>, std::unique_ptr<Xa_state_list::allocator>,
9433 std::unique_ptr<Xa_state_list::list>, std::unique_ptr<Xa_state_list>>(
9434 7758 std::move(mem_root), std::move(map_alloc), std::move(xid_map),
9435
1/2
✓ Branch 0 taken 7758 times.
✗ Branch 1 not taken.
23274 std::move(xa_list));
9436 7758 }
9437